【面试题】Vue面试题整理
创始人
2024-05-29 13:44:30
0

1. v-show 和 v-if 的区别?

  • v-if 指令用于条件渲染,它会根据表达式的值的真假来决定是否渲染元素。如果表达式的值为 false,则该元素不会被渲染并且也不会保留在 DOM 中。
  • v-show 指令用于条件展示,它不会从 DOM 中删除元素,只是简单地使用 CSS 属性 display 控制元素的显示和隐藏。
  • v-if 更适用于在运行时动态添加/删除元素,而 v-show 更适用于频繁切换显示和隐藏。

2. 为何在 v-for 使用 key?

  • 当 Vue 使用 v-for 指令更新被迭代的元素时,会通过 diff 算法检测哪些元素已经被添加、删除或移动,以便只更新需要更新的元素,而不是重新渲染整个列表。为了实现这个检测机制,Vue 使用每个元素的 key 作为跟踪它们的标识。
  • 在为元素指定 key 时,key 的值应该是一个字符串或数值类型。它的值应该是唯一的,且不会随着元素的重新排序而改变。如果没有为元素指定唯一的 key,Vue 会使用元素的索引作为默认 key,但是元素的索引可能会发生变化,因此使用索引作为 key 会导致潜在的渲染错误。

3. 描述Vue组件的生命周期

  • 在 Vue 中,组件生命周期指的是组件从创建到销毁的整个过程,包含了多个阶段和钩子函数。钩子函数在组件的不同阶段做出相应的处理,实现对组件的控制。Vue 组件的生命周期包含四个阶段:创建阶段、更新阶段、销毁阶段、激活\停用阶段。
  • 创建阶段的主要工作是创建组件实例并将组件实例渲染到页面中。该阶段会调用四个钩子函数,即 beforeCreate、created、beforeMount、mounted。beforeCreate 函数在组件实例初始化之后,数据观测和事件配置之前被调用,此时组件实例尚未创建,不能访问 data 和 methods 等数据和方法。created 函数在组件实例创建完后被立即调用,此时组件实例已经创建,可以访问 data 和 methods 等数据和方法,但此时组件尚未被挂载到 DOM 中。beforeMount 函数在组件挂载之前被调用,此时组件已经完成了模板编译,但尚未将其渲染到页面中。mounted 函数在组件挂载完成后被调用,此时组件已经被渲染到页面中,可以进行需要访问 DOM 的操作。
  • 更新阶段调用 beforeUpdate 和 updated 钩子函数。beforeUpdate 函数在组件更新之前被调用,此时组件的数据已经发生了变化,但是 DOM 尚未重新渲染,这个阶段可以进行组件数据更新前的处理工作,例如计算属性的更新、深度监听数据的变化等。updated 函数在组件更新之后被调用,此时组件的 DOM 已经重新渲染,数据观测(data observer)和 event/watcher 事件已经重新开始,可以进行一些需要访问更新后 DOM 元素的操作。
  • 销毁阶段调用 beforeDestroy 和 destroyed 钩子函数。beforeDestroy 函数在组件实例销毁之前被调用,此时组件实例仍然可以访问,该阶段可以进行一些组件销毁前的处理工作,比如清除定时器、取消事件监听等。destroyed 函数在组件销毁之后被调用,此时组件实例已经被销毁,无法再访问组件实例中的任何数据和方法。
  • 激活/停用阶段调用 activated 和 deactivated 钩子函数。activated 函数在 keep-alive 组件被激活时调用。deactivated 函数在 keep-alive 组件被停用时调用。

4. Vue父子组件生命周期执行顺序

在父组件中调用子组件时,组件的生命周期执行顺序如下:

  1. 父组件开始创建阶段,首先会调用父组件的 beforeCreate 和 created 函数。
  2. 父组件进入模板编译阶段,此时会先调用父组件的 beforeMount 函数,然后会递归遍历子组件的模板,创建子组件实例,并调用子组件的 beforeCreate 和 created 函数。
  3. 当子组件实例创建完成后,父组件会调用子组件的 beforeMount 函数,将子组件渲染到父组件的模板中,渲染完成会先调用子组件的 mounted 函数。当子组件全部渲染完成后,会调用父组件的 mounted 函数。此时父组件和子组件已经挂载完成。
  4. 当子组件的数据发生变化时,首先调用父组件的 beforeUpdate 函数,然后依次调用子组件的 beforeUpdate 和 updated 函数,当子组件全部更新完成后,会调用父组件的 updated 函数。当父组件的数据发生变化时,如果这些数据被传递给子组件作为 props 属性,那么会调用子组件的 beforeUpdate 和 updated 函数;如果父组件中的数据改变没有通过 props 属性传递给子组件,那么不会调用子组件的 beforeUpdate 和 updated 函数,只会调用父组件的 beforeUpdate 和 updated 函数。
  5. 当父组件被销毁时,子组件也会随之销毁,首先调用父组件的 beforeDestory 函数,然后依次调用子组件的 beforeDestory 和 destoryed 函数,当子组件全部销毁后,会调用父组件的 destoryed 函数。

5. Vue组件如何通讯?

  • 父到子传值:父到子的传值可以通过在子组件中添加 props 配置项来完成,props 配置项的值可以是一个数组,数组中的元素用于接收父组件传递过来的数据,在父组件中通过子组件的标签属性来传递这些数据。我们可以把父到子传值理解成函数的封装和调用,props 数组中的元素是函数的形参,在使用子组件的时候,传入父组件的数据作为实参。
  • 子到父传值:子到父的传值可以通过自定义事件完成。在子组件中,通过 $emit 方法触发自定义事件,$emit 方法的第一个参数是自定义事件的名称,之后的参数则是要传递的数据。在父组件中,使用 v-on 指令来监听这个自定义事件,v-on 指令的参数是自定义事件的名称,值是一个函数,这个函数会在自定义事件被触发时被执行,函数的参数就是子组件传递过来的数据。
  • Vuex:Vuex 是 Vue.js 的官方状态管理库,用于管理应用程序中的共享状态,可以解决应用程序中状态管理复杂性的问题。Vuex 中有四个核心概念:1. state,用于存放数据,通过 this.$store.state.xxx 来访问。2. getters,相当于组件的计算属性,里面的函数自带一个 state 参数,通过 this.$store.getters.xxx 来访问。3. mutations,在 mutations 中定义方法修改 state 中的数据,定义的方法必须的同步的,可以通过 this.$store.commit("xxx") 来调用。4. actions,用于处理异步操作,但是 actions 不能修改数据,需要在 actions 定义的函数中提交 mutations,因为只有 mutations 中定义的方法能够修改数据,通过 this.$store.dispatch("xxx") 来调用。

6. 描述Vue组件渲染和更新的过程

Vue组件渲染和更新的过程简单地概况为以下几个步骤:

  1. 初始化组件实例:在渲染一个组件之前,Vue会创建一个组件实例,并将组件的选项对象进行合并、处理,最终形成一个组件实例的配置对象。
  2. 渲染组件:Vue将组件实例的配置对象转化为一个渲染函数,并执行该渲染函数,生成一个虚拟DOM树。此时,Vue会对虚拟DOM树进行初次渲染,将组件显示在页面上。
  3. 监听数据变化:当组件实例中的响应式数据发生变化时,Vue中的渲染watcher会立即检测到这些变化,并重新计算组件的渲染函数,生成一个新的虚拟DOM树。
  4. 对比新旧虚拟DOM树:Vue会将新生成的虚拟DOM树和上一次渲染时生成的虚拟DOM树进行比较,找出需要更新的部分。
  5. 更新组件:Vue只会更新旧虚拟DOM树中有差异的部分,使组件达到更新的效果。

7. 双向数据绑定v-model的实现原理

  • v-model 是 Vue.js 中常用的指令,通过该指令可以将表单元素的值与 Vue 实例的属性进行双向绑定。当用户输入表单元素的值时,Vue 会自动更新实例的属性,反之亦然。
  • 使用 v-model 时,只需要在需要绑定的表单元素或组件上加上 v-model 指令,并把它的值设置为需要绑定的属性即可,代码如下:
``
  • v-model 指令实际上是一个语法糖,它相当于同时使用了一个名为 value 的属性 和 一个名为 input 的事件。上面的代码等价于:
``

其中,:value="message" 是将组件的 value 属性与组件实例的 message 属性绑定起来;@input="message = $event.target.value" 则是将组件的 input 事件与一个函数绑定起来,这个函数将当前表单元素的值赋给组件实例的 message 属性。

8. 如何理解MVVM模式?

  • 传统的组件渲染是静态渲染,数据更新需要操作DOM。Vue框架采用 MVVM(Model-View-ViewModel) 模式来管理应用程序的数据模型(Model)和视图界面(View)之间的交互,即数据驱动视图,达到减少DOM操作的目的。
  • MVVM的基本思想是将 Model 和 View 进行解耦(Decoupling),也就是将 Model 和 View 分离开来,使得它们之间的依赖关系降到最小。然后通过 ViewModel 来协调它们之间的通信。当 Model 变化时,我们不需要手动更新 View,而是可以通过 Vue 的响应式机制,让 Vue 自动更新 View。同样,当用户与 View 交互时,我们也不需要手动修改 Model,而是可以通过 Vue 的指令和事件机制,让 Vue 自动更新 Model。这种解耦机制使得我们可以更加专注于业务逻辑的实现,而不需要过多地关注 View 和 Model 之间的细节。
    在这里插入图片描述
  • Model:Vue应用程序中的数据模型,通常是一个JavaScript对象或数组。这些数据模型被存储在Vue实例的 data 属性中。
  • View:Vue应用程序中的视图界面,通常由 HTML模板 和 Vue指令 组成。Vue的模板语法允许开发人员在HTML中绑定数据以及表达式,从而实现视图的动态更新。
  • ViewModel:ViewModel 是Vue应用程序的核心,它是一个Vue实例,它充当 Model 和 View 之间的桥梁。ViewModel 负责业务逻辑以及管理数据,它可以将 Model数据 绑定到 View 上,同时也可以响应 View 上的事件和用户交互。ViewModel 通过 Vue的响应式机制监听 Model数据 的变化,并自动更新 View。

9. 计算属性computed有何特点?

在Vue实例中,计算属性 computed 是一种用于实时计算 Vue 组件属性值的便捷方式。它可以缓存计算结果,只有在计算属性依赖的响应式数据发生改变时才重新计算;当依赖的数据没有改变时,计算属性不再计算,直接返回缓存的结果,提高了组件渲染的性能。

10. 为何组件中的data必须是一个函数?

在Vue中,每个组件实例都拥有自己的作用域和状态。如果 data 选项是一个简单的对象,那么该组件的实例都会共享这个对象,这样就会出现一个实例更改数据后导致另一个实例中的数据被改变的问题。将 data 定义为一个函数,每个组件实例在创建时都会调用该函数来返回一个对象,从而确保每个实例都拥有自己的数据。同时,Vue 在内部会对这个函数进行封装,确保它只被调用一次,从而避免不必要的性能损失。

11. Ajax请求应该放在哪个生命周期?

  • Ajax(Asynchronous JavaScript and XML) 是一种网络请求方式,可以通过 JavaScript 和 XML 实现异步传输数据。Ajax 可以在不重新加载整个页面的情况下,通过异步请求服务器上的数据,并将数据局部更新到页面上,从而实现局部刷新的效果,提高用户的交互体验。
  • 一般 Ajax 请求会在页面加载完成后,由用户触发某个事件时执行,也就是 mounted 生命周期后执行。这种方式可以避免在页面加载时对服务器进行不必要的请求,提高页面加载速度和用户体验。

12. 如何将父组件所有props传给子组件?

在调用子组件时,绑定 $props 属性。


13. 如何自己实现v-model?

对于一个自定义组件,如果要实现 v-model 双向绑定,需要通过 自定义v-model 的方式实现。自定义v-model 需要在自定义组件中使用 model选项 来配置 value属性 和 input事件的名称。并在组件模板中使用v-bind 将 value属性 绑定到 input元素的value属性上,并通过 v-on 监听 input事件,当input事件触发时将表单元素的值通过 $emit 方法发送出去。这样就可以使用v-model语法糖来实现自定义组件的双向绑定了。

14. 多个组件有相同逻辑,如何抽离?

  • 在Vue中,mixin(混入)是一种将多个组件之间共享的逻辑抽象出来并进行重用的机制。通过定义一个mixin对象,可以将其应用于多个组件中,从而为这些组件提供相同的属性、方法、生命周期钩子等。
  • mixin 是一个普通的 JavaScript 对象,可以包含各种属性和方法,例如data、computed、methods、created等。在组件中,通过定义 mixins 选项来应用一个或多个 mixin。当组件引用了一个或多个 mixin 时,mixin 中定义的属性和方法会被混合到该组件中,这些属性和方法与组件自生定义的属性和方法会合并成一个新的对象。如果 mixin 中定义的属性或方法与组件自身定义的属性或方法名称冲突,则以组件自身的属性或方法为准。
  • 使用 mixin 可以将组件中相同的逻辑代码进行抽象和复用,避免了代码重复和冗余。但是,mixin 的使用也存在一些问题,比如,多个 mixin 可能会造成命名冲突。变量来源不明确,不利于代码阅读。mixin 和组件可能会出现多对多的关系,复杂度高。

15. 何时使用异步组件?

异步组件与常规组件的不同之处在于,异步组件只有在需要的时候才会被加载,而不是在应用程序初始化时就被全部加载。异步组件的应用场景是:当某个组件的体积比较大时,例如Echarts文件,如果应用初始化时就加载,会非常慢,严重影响性能。此时可以将该组件设置为异步组件,在需要使用该组件时,再加载该组件。异步组件通过 import() 函数引入。

16. 何时需要使用keep-alive?

  • keep-alive是Vue内置的一个组件,可以将其用于需要缓存的动态组件,避免每次重新渲染时都要执行组件的 created、mounted、destoryed等钩子函数,从而提高应用程序的性能。
  • keep-alive组件可以包裹动态组件,使其被缓存。被缓存的组件在组件切换时并不会被销毁,而是被保留在内存中,下次需要渲染时直接从缓存中读取组件实例,避免了组件的重新创建和重新渲染。

17. 何时需要使用beforeDestory?

beforeDestroy 函数在组件实例销毁之前被调用,此时组件实例仍然可以访问,该阶段可以进行一些组件销毁前的处理工作,比如清除定时器、取消事件监听 $off、解绑自定义事件 event.$off 等。

18. 什么是作用域插槽?

  • 作用域插槽(scoped slot)是Vue中的一种高级插槽技术。父组件希望使用子组件中的数据作为插槽中的内容,可以使用作用域插槽。
  • 在父组件中,使用