Skip to content

Vue面试题

1. Vue中的双向绑定

双向绑定是模板中数据和实例中数据的双向绑定,当数据发生变化时,模板会自动更新,当模板发生变化时,数据也会自动更新。

模板中使用双向绑定的语法是 v-model,实际是语法糖,等价于 :value@input 事件的组合。当模板数据更新时,会触发 @input 事件,更新实例数据。

实例数据也就是响应式数据,当实例数据发生变化时,会触发视图的响应式更新。

注意:

  • 双向绑定只适用于表单元素(如输入框、选择框等),不适用于普通的DOM元素。
  • 对于不同表单元素,双向绑定被不同的属性绑定。
    • 输入框、文本域使用 v-model 绑定 value 属性。
    • 选择框使用 v-model 绑定 selected 属性。
    • 复选框使用 v-model 绑定 checked 属性。
  • Vue2 中使用 v-model 绑定的属性是 value,而 Vue3 中使用 v-model 绑定的属性是 modelValue
  • v-model可以在组件中使用,Vue2只能使用一个 v-model,而 Vue3 中可以使用多个 v-model
  • Vue2 中想要使用多个 v-model,可以使用 :value2.sync

2. vue中key的作用

什么是key

在vue中,key是虚拟DOM节点(VNode)的唯一标识。

当Vue更新视图时,会进行虚拟DOM diff算法。它会拿旧的VNode树与新的VNode树进行对比,找出哪些节点可以复用,哪些节点需要被创建或删除。

如果两个节点的key 和 节点的类型 都相同,那么Vue会认为这两个节点是相同的节点,直接复用;否则,Vue会认为这两个节点是不同的节点,销毁旧节点,创建新节点。

不设置key

默认是不设置key的,Vue会尽可能地复用相同类型的节点。这样是高效的,但只适用于列表输出的结果不依赖子组件状态或临时DOM状态(例如表单输入值)。

否则可能会导致错误的节点被复用,如: 在列表中插入或删除元素时,Vue 可能错误地复用相邻节点的 DOM,导致状态错乱(如输入框内容错位)。

设置key

根据 key 的变化顺序来重新排列元素,并且将始终移除/销毁 key 已经不存在的元素。

同一个父元素下的子元素,key 必须是唯一的,不然会导致渲染异常。

官方推荐在列表渲染时,使用唯一的 key 来标识每个节点,这可以帮助 Vue 更准确地进行 DOM diff 操作,提高渲染效率。

3. 什么时候用ref,什么时候用reactive?

ref和reactive的区别

ref 用于定义基本类型的响应式数据,如字符串、数字、布尔值等。 reactive 用于定义引用类型的响应式数据,如对象、数组等。

reactive不能直接赋值,只能修改对象的属性。而ref可以直接赋值。

建议:使用ref,但当只需要响应式数据对象时,不修改,可以使用reactive。

4. Vue3中的Compositon API的优势是?

  • Vue2中所有属性都是通过 this 访问的,this存在指向明确问题。
  • Vue2中很多未使用方法或属性依旧被打包,并且所有全局API都是在Vue对象上公开。Composition API 对tree-shaking更友好。
  • 组件逻辑共享问题,Vue2中通过mixin实现,但是会有数据来源不清晰,命名冲突等问题,而Vue3中通过Composition API提取公共逻辑到单独的函数中,实现了逻辑的复用,更方便。

5. Vue2和Vue3的的区别?

  1. Vue3更新注重模块上的拆分,在2.0中无法使用单独模块,想要使用响应式部分,需要引入完整的Vue.js,而Vue3中可以使用单独响应式模块。
  2. Vue2中很多方法是挂载在Vue对象上的,导致没使用也会打包。Vue3可以通过构建工具(如Webpack)的tree-shaking功能,只打包使用到的方法。
  3. Vue3允许自定义渲染器,扩展方便。
  4. Vue3中使用Proxy实现响应式,是惰性的,而Vue2中使用Object.defineProperty实现响应式,是立即的循环所有属性。
  5. Vue3的响应式可以支持动态添加或删除属性,而Vue2中需要通过手动操作。
  6. Diff算法重写。
  7. Vue3模板优化,Vue3中使用了静态提升技术,将静态节点提取出来,避免每次渲染都创建相同的节点。

6. Vue3.3中(没有defineModel)自定义组件的v-model,不用watch,如何监听父组件的值变化?

这里主要是computed的set方法。

ts
const props = defineProps<{ modelValue: any }>();
const emit = defineEmits<{
  (e: 'update:modelValue', value: any): void;
}>();
const model = computed({
  get() {
    return props.modelValue;
  },
  set(value: any) {
    emit('update:modelValue', value);
  }
});

7. watch中请求数据时,如果依赖的属性变化,发送了两次请求,如何解决?

ts
watch(() => props.modelValue, async (newValue, oldValue, onCleanup) => {
  let isCurrent = true;
  const resp = await fetchData(newValue);
  onCleanup(() => {
    isCurrent = false;
  });
  if (isCurrent) {
    // 处理数据
  }
});

watchEffect(async (onCleanup) => {
  const { response, cancel } = doAsyncWork(newId)
  // 如果 `id` 变化,则调用 `cancel`,
  // 如果之前的请求未完成,则取消该请求
  onCleanup(cancel)
  data.value = await response
});

8. setup函数的理解

  1. setup函数是Vue3中组件的入口函数,在组件实例创建时调用。
  2. setup函数中可以定义响应式数据、计算属性、方法等。
  3. setup函数中不能使用this,因为this在setup函数中是undefined。
  4. setup函数中可以返回一个对象,对象中的属性会被合并到组件实例中。
  5. setup函数中可以返回一个函数,该函数会作为组件的渲染函数。

9. 为什么需要虚拟 DOM?

  1. 由于Vue的更新是组件级别更新的,所以虚拟 DOM 可以实现高效的 DOM diff 算法,只更新需要改变的部分,避免全量更新导致的性能问题。
  2. 虚拟 DOM 是一个JS对象,可以实现跨平台渲染,如服务器端渲染、移动端渲染等。