1. Vue 的生命周期有哪些,每个阶段分别做什么操作?
- beforeCreate:
- 在实例初始化之后、数据观测和事件配置之前被调用。
- 此时数据对象 data 和事件(methods)都还未初始化。
- 一般不在此阶段进行数据初始化和 DOM 操作。
- created:
- 在实例创建完成后被立即调用。
- 实例已完成数据观测、属性和方法的运算,但尚未挂载到 DOM 上。
- 可以进行异步操作、数据初始化以及监听数据的变化等操作。
- beforeMount:
- 在挂载开始之前被调用:相关的 render 函数首次被调用。
- 在此阶段,模板编译已完成,但尚未将生成的 DOM 插入页面。
- mounted:
- 在挂载完成后被调用。
- 在此阶段,组件已经被挂载到页面中,DOM 元素已经生成,可以进行 DOM 操作、访问 DOM 元素、发送网络请求等。
- beforeUpdate:
- 在数据更新之前被调用,发生在虚拟 DOM 重新渲染和打补丁之前。
- 在此阶段,数据已经更新,但是尚未重新渲染到视图中。
- updated:
- 在数据更新之后被调用,发生在虚拟 DOM 重新渲染和打补丁之后。
- 在此阶段,组件的 DOM 已经更新,可以进行一些操作,如数据同步、手动修改 DOM 等。
- beforeDestroy:
- 在实例销毁之前调用。在这一步,实例仍然完全可用。
- 可以在这里进行清理工作,比如取消定时器、清除非 Vue.js 的事件监听器等。
- destroyed:
- 在实例销毁之后调用。在这一步,所有的事件监听器和子实例被移除。
- 在此阶段,组件已经被销毁,数据绑定和监听被清除,但 DOM 元素还存在。
2. Vue组件通信方式有哪些?
- Props 和 Events: 父组件通过 props 向子组件传递数据,子组件通过 events 向父组件发送消息。这是最基本和常见的组件通信方式。
- 自定义事件: 使用 Vue 的 $emit() 方法在子组件中触发自定义事件,然后在父组件中监听并处理这些事件。
- 事件总线(Event Bus): 创建一个全局的 Vue 实例作为事件总线,通过这个实例来触发和监听事件,不管组件的层级关系如何都可以进行通信。
- Vuex 状态管理: 对于大型应用程序,使用 Vuex 可以更方便地管理组件之间共享的状态。Vuex 提供了集中式存储管理,并提供了一些额外的 API 来实现组件之间的通信。
- $refs: 在父组件中通过 $refs 来访问子组件的实例,从而直接调用子组件的方法或访问子组件的数据。
- Provide 和 Inject: 祖先组件通过 provide 来提供数据,然后后代组件通过 inject 来注入提供的数据。这种方式可以跨越多层级的组件进行通信。
- $attrs 和 listeners: 父组件可以通过 v-bind="attrs" 将所有属性传递给子组件,通过 v-on="$listeners" 将所有监听器传递给子组件,从而实现透传属性和事件的目的。
- $parent 和 $children: 在某些情况下,您可以直接通过 $parent 或 $children 访问父组件或子组件的实例,以实现通信。
3. Vuex 的核心属性及作用?
- State(状态): Vuex 的核心是一个存储中心,称为状态(State),它包含了应用中所有组件的共享数据。可以将 Vuex 的状态想象为应用的单一数据源,组件中的数据都应该从这个状态中获取。
- Getters(获取器): Getters 允许我们在 Vuex 的状态上进行计算操作,并且可以派生出一些新的状态。它类似于 Vue 组件中的计算属性,可以在获取数据时进行一些逻辑处理。
- Mutations(突变): Mutations 是用来修改 Vuex 的状态的方法。它们是同步的,每个 Mutation 都有一个字符串类型的事件类型和一个回调函数,用于修改状态。
- Actions(动作): Actions 类似于 Mutations,不同之处在于 Actions 提交的是 Mutation 而不是直接变更状态,可以包含任意异步操作。它们是用于处理业务逻辑的地方,例如处理异步请求、封装多个 Mutation 等。
- Modules(模块): Vuex 允许将 Store 分割成模块(Modules),每个模块拥有自己的 State、Getters、Mutations 和 Actions,可以更好地组织代码和管理复杂的状态。
4. Vue 的监听属性和计算属性的区别?
监听属性用于监视 Vue 实例上的数据变化,并在数据变化时执行一些自定义的操作。当需要在数据发生变化时执行异步或复杂的操作时,通常会使用监听属性。监听属性是一个对象,其属性是要监听的数据,值是一个函数,用于处理数据变化时的逻辑。
计算属性用于基于已有的数据衍生出新的数据,并且只有在相关依赖发生改变时才会重新计算。计算属性是一个函数,在 Vue 实例中使用 computed 选项来定义。计算属性会缓存计算结果,只有在相关依赖发生改变时才会重新计算,并且在多次访问时只会计算一次。
区别如下:
- 响应性: 计算属性具有缓存机制,只有在依赖的数据发生变化时才会重新计算,而监听属性没有缓存机制,每次数据变化都会触发监听函数。
- 用法: 计算属性适用于基于已有数据衍生出新的数据,而监听属性适用于需要在数据变化时执行异步或复杂的操作。
- 语法: 计算属性是一个函数,而监听属性是一个对象,其属性是要监听的数据,值是一个处理函数。
5. Vue的导航守卫有哪一些?
导航守卫是一组用于控制路由导航的钩子函数,允许您在路由发生变化时执行一些逻辑。Vue Router 提供了多种导航守卫,包括全局导航守卫、路由独享的守卫和组件内的守卫。
Vue Router 中常用的导航守卫:
- 全局守卫
- beforeEach: 在路由切换开始时执行,常用于进行全局的身份验证、权限验证、路由跳转等操作。
- beforeResolve: 在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后执行。这个守卫不会等待异步路由组件解析完成就立即执行,适合在确保所有异步组件都被解析完毕后执行一些逻辑。
- afterEach: 在导航完成后(即在所有组件渲染完成后)执行,常用于页面统计、日志记录等操作。
- 路由独享的守卫
- beforeEnter: 在路由配置中直接定义的导航守卫,仅在特定路由上生效。
- 组件内的守卫:
- beforeRouteEnter: 在路由进入该组件前执行,可以访问不到组件实例 this,但可以通过回调函数访问到组件实例。
- beforeRouteUpdate: 在当前路由改变,但是该组件被复用时执行,常用于同一组件不同参数间的切换。
- beforeRouteLeave: 在导航离开该组件的对应路由时执行,常用于在用户离开当前页面前进行确认操作或保存未提交的数据。
6. Vue2 与 Vue3 有什么区别?
- 性能优化:Vue 3 在性能方面进行了大幅优化,包括虚拟 DOM 的重写、编译器的升级、组件实例的优化等,使得 Vue 3 在渲染速度和内存占用方面都有明显的提升。
- Composition API:Vue 3 引入了 Composition API,它是一种新的组件 API 设计,提供了更灵活、更可复用的组件逻辑组织方式,使得组件逻辑更清晰、更易于维护。
- 响应式系统的改进:Vue 3 中的响应式系统经过了重构和优化,使用了 Proxy 来代替 Object.defineProperty,提供了更好的性能和更完整的类型推断。
- TypeScript 支持:Vue 3 对 TypeScript 的支持更加完善,包括更好的类型推断、更全面的类型定义等,使得使用 TypeScript 开发 Vue 应用更加便捷。
- 静态提升和 Tree-shaking:Vue 3 改进了静态提升和 Tree-shaking,使得打包出的代码更小、更高效,同时也提高了应用的性能。
- Teleport 和 Suspense:Vue 3 引入了 Teleport 组件和 Suspense 组件,用于更灵活地控制组件的挂载位置和处理异步组件加载时的 loading 状态。
- Fragment 和 Portal:Vue 3 支持 Fragment 和 Portal,允许开发者更灵活地组织组件的结构和布局。
- 性能警告:Vue 3 引入了性能警告,在开发模式下,如果发现组件渲染存在性能问题,会在控制台给出警告,帮助开发者优化代码。
7. Vue常用指令有哪些?
- v-bind: 用于动态绑定 HTML 属性,可以简写为 :
- v-model: 用于实现表单元素和应用程序状态之间的双向数据绑定,常用于表单输入元素
- v-if / v-else: 用于根据表达式的真假条件来条件性地渲染元素,v-else 表示否定条件
- v-show: 类似于 v-if,但是使用 CSS 的 display 属性来控制元素的显示和隐藏,而不是直接添加和移除元素
- v-for: 用于遍历数组或对象,生成重复的 HTML 元素
- v-on: 用于监听 DOM 事件,执行相应的 JavaScript 代码,可以简写为 @
- v-pre: 跳过该元素和其子元素的编译过程,用于优化渲染性能
- v-cloak: 用于在 Vue 实例加载之前隐藏未编译的 Mustache 标签,避免页面闪烁
- v-text / v-html: 分别用于替代元素的 textContent 和 innerHTML 属性,用于动态设置元素的文本内容或 HTML 内容
- v-once: 只渲染元素和组件一次,不会随着数据的变化重新渲染
- v-slot: 用于命名插槽和作用域插槽的语法,用于更灵活地定义组件的内容分发
8. v-if 和 v-show 有什么区别?
v-if值为false时,会销毁元素,而v-show则仅是通过display来控制元素的显示和隐藏。
v-if 适用于需要对性能进行优化的场景,因为它可以避免不必要的 DOM 渲染和事件监听;v-show适用于对性能要求不高,但需要频繁切换显示和隐藏的场景。
9. v-for为什么要加一个key?
在使用 v-for 指令对数组或对象进行循环渲染时,通常需要为每个遍历的元素添加一个唯一的 key 属性。这是因为 Vue.js 在进行列表渲染时,会尽可能地高效更新 DOM,以减少不必要的 DOM 操作。而使用 key 属性可以帮助 Vue.js 进行有效的列表渲染和更新。
10. keep-alive是什么?有哪几个生命周期阶段?
<keep-alive> 是 Vue.js 提供的一个抽象组件,用于将动态组件缓存到内存中,以便在组件切换时保留其状态或避免重新渲染。当一个包裹在 <keep-alive> 内的动态组件被切换时,其状态将被保留,而不会被销毁和重新创建,以提高性能和用户体验。
生命周期:
- activated: 在被包裹的动态组件被激活时调用。这意味着组件被缓存并且再次被显示出来。例如,当组件从 <keep-alive> 缓存中被加载出来时。
- deactivated: 在被包裹的动态组件被停用时调用。这意味着组件被缓存但不再被显示。例如,当组件被切换出去并被缓存起来时。
11. EventBus是什么东西?
EventBus(事件总线)是一种设计模式,用于在应用程序的不同组件之间进行通信。它允许组件在不直接相互引用的情况下进行通信,从而提高了组件之间的解耦性。
在 Vue.js 中,EventBus 是一个 Vue 实例,可以用于在组件之间发送和接收事件。通常情况下,我们可以通过在 Vue 原型上添加一个新的 Vue 实例来创建 EventBus,然后在组件中通过该实例来发送和监听事件。
12. 父子组件生命周期执行顺序是怎么样的?
- beforeCreate
- created
- beforeMount
- 子组件的 beforeCreate
- 子组件的 created
- 子组件的 beforeMount
- 子组件的 mounted
- mounted
13. Vue的双向绑定原理是什么,关键点在哪里?
- 数据劫持(响应式系统): Vue 使用了 Object.defineProperty() 方法来劫持(或监听)数据的属性,当数据发生变化时,可以通知相关的视图更新。这个过程是在 Vue 实例化阶段进行的,即在 Vue() 函数内部进行。
- 虚拟 DOM: Vue 使用虚拟 DOM 来描述视图,当数据发生变化时,Vue 会通过比较新旧虚拟 DOM 树的差异,最小化地更新实际 DOM,以提高性能。
- 模板编译: 在 Vue 模板编译过程中,会将模板转换成渲染函数(render function),这个渲染函数返回的是一个 VNode(虚拟节点)树,描述了视图的结构和内容。
- 发布-订阅模式: Vue 使用了发布-订阅模式来实现数据的响应式更新。当数据发生变化时,会通知相关的订阅者(观察者),从而触发相应的更新操作。这个过程是在数据劫持过程中实现的,即当属性的 getter 或 setter 被访问或修改时触发。
- 双向绑定: 双向绑定是指数据的变化可以影响视图的更新,同时视图的变化也可以影响数据的更新。在 Vue 中,通过 v-model 指令可以实现表单元素和数据的双向绑定,当表单元素的值发生变化时,会更新数据,反之亦然。
14. vue3为什么要用proxy替代defineProperty?
- 更全面的拦截功能: Proxy 提供了更多的拦截器,比 Object.defineProperty 更加灵活,可以拦截更多类型的操作,包括对象的删除、添加、枚举等。
- 更好的性能: 在特定情况下,使用 Proxy 可以比 Object.defineProperty 更高效。在 Vue 3 中,Vue 使用了基于 Proxy 的响应式系统,在大多数情况下,性能优于 Vue 2 中基于 Object.defineProperty 的实现。
- 避免了一些限制: 使用 Proxy 可以避免 Object.defineProperty 的一些限制,比如不能监视数组的变化、不能监视动态添加的属性等问题。
- 更好的 TypeScript 支持: Proxy 对 TypeScript 的支持更加友好,可以更准确地推断类型和提供类型安全。
- 更易于维护和扩展: Proxy 提供了更清晰和直观的 API,使代码更易于理解和维护,并且更容易进行扩展和定制。
15. Vue有哪些钩子,如何自定义钩子?
- beforeCreate: 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
- created: 在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。
- beforeMount: 在挂载开始之前被调用:相关的 render 函数首次被调用。
- mounted: el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。
- beforeUpdate: 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。
- updated: 由于数据更改导致的虚拟 DOM 重新渲染和打补丁后调用。
beforeUnmount (Vue 2.x) / beforeUnmount (Vue 3.x): 在卸载组件之前调用。
- unmounted: 组件被卸载后调用。
- errorCaptured: 捕获子孙组件的错误。工作方式类似于全局错误处理器。
要自定义钩子,您可以使用 Vue.mixin() 方法或编写全局插件。例如,使用 mixin 可以这样自定义一个钩子:
Vue.mixin({`
`created:` `function` `()` `{`
`// 任意自定义逻辑`
` console.log('Custom created hook');`
`}`
`});
16. Vue中的mixin
在 Vue 中,Mixin 是一种可复用的组件选项对象。它允许您在多个组件中共享和重用代码,从而实现代码的复用和组件的扩展。Mixin 提供了一种在组件之间共享代码的方式,可以将一些通用的逻辑、数据和方法提取到 Mixin 中,然后将其混入到需要的组件中。
Mixin 可以包含组件选项对象中的任何选项,包括 data、methods、computed、watch、生命周期钩子等。
优势:
- 代码重用: Mixin 允许在多个组件中共享相同的逻辑和功能,减少重复编写代码的工作量。
- 灵活性: 可以根据需要将不同的 Mixin 组合在一起,实现不同的功能组合。
- 解耦逻辑: 可以将一些通用的逻辑和功能抽象为 Mixin,从而使组件更加简洁和专注于自身的业务逻辑。
- 扩展性: 可以在不修改原始组件代码的情况下,通过混入额外的 Mixin 来扩展组件的功能。
17. Vue路由模式有哪些 ? 原理 是什么 ?
哈希模式(Hash Mode):
- 哈希模式是 Vue Router 的默认模式,也是较老的一种路由模式。
- 由于哈希部分的改变不会重新加载页面,因此在单页应用中,哈希模式能够很好地支持前端路由。
- 原理:在哈希模式中,路由信息被保存在 URL 的哈希部分(即 # 号之后),当用户点击页面内的链接时,哈希部分会改变,但浏览器不会向服务器发送请求,而是通过监听 hashchange 事件来进行路由的切换。Vue Router 会使用 window.addEventListener('hashchange', callback) 监听 hash 的改变,一旦 hash 发生变化,就会触发相应的路由切换。
历史模式(History Mode):
- 历史模式使用 HTML5 的 History API 来管理路由状态。
- 在历史模式中,路由信息以常规的 URL 形式显示,而不需要 # 号,看起来更加美观。
- 历史模式下,需要服务端的支持来配置处理前端路由请求的路径。
- 原理:当用户点击页面内的链接时,浏览器会向服务器发送请求,服务器需要配置处理前端路由请求的路径,以返回正确的页面。Vue Router 使用 History API 提供的 pushState() 和 replaceState() 方法来添加和修改历史记录,以及监听浏览器的 popstate 事件来响应历史记录的变化。