Vue面试题

123 阅读5分钟

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

  • v-if直接在dom结构上创建和销毁
  • v-show通过设置样式display来显示和隐藏,一直存在dom结构中
  • 对于频繁切换建议使用v-show,不频繁切换操作的使用v-if

2. 为何v-for中要用key

虚拟dom的比对根据key做关联,如果key一样可以实现复用,提高性能

3. 不建议使用index做key

因为index存在不稳定性,不容易实现复用

4. 描述Vue组件生命周期(有父子组件的情况)

  • Vue2中的生命周期:
    • beforeCreate
    • created
    • beforeMount
    • mounted
    • beforeUpdate
    • updated
    • beforeDestroy
    • destroyed
  • Vue3中的生命周期
    • onBeforeCreate()
    • onCreated()
    • onBeforeMount()
    • onMounted()
    • onBeforeUpdate()
    • onUpdated()
    • onBeforeUnmount()
    • onUnmounted()
  • 挂载阶段: beforeMount父 -> beforeMount子 -> mounted子 -> mounted父
  • 更新阶段 beforeUpdate父 -> beforeUpdate子 -> updated子 -> updated父
  • 销毁阶段 beforeDestroy父 -> beforeDestroy子 -> destroyed子 -> destroyed父

ad42e2e3e86b432ab39d3591540bd5ed_tplv-k3u1fbpfcp-zoom-1.png

5. Vue组件如何通讯

  • 父子组件通讯

    • 父组件通过props向子组件传递参数
    • 子组件通过$emit向父组件触发事件
  • 自定义事件(总线机制)

    • 使用vue实例自带的onon、emit、$off进行通讯
      import Vue from 'vue';
      export default new Vue();
    
      import event from './event.js';
    
      event.$emit('getInfo', "你好");
    
      event.$on('getInfo', this.addGetInfo);
      event.$off('getInfo', this.addGetInfo);
      注意:在beforeDestroy(){}生命周期及时销毁自定义事件,避免内存泄漏
      event.$off()
    
  • Vuex

    Vuex在Vue2和Vue3中的使用

6. 自定义v-model

详细介绍

7. mixin的作用及问题

  • 作用:提取组件间的公共逻辑
  • 问题:
    • 多变量来源不明确,不利于阅读
    • 多个mixin可能回造成变量冲突
    • mixin和组件可能存在多对多关系,复杂度较高
  • 使用
// mixin.js
export default {
  data(){
    return {
      name: "你好我是mixin"
    }
  },
  methods: {
    change(){
      this.name = "我已经修改了呦"
    }
  }
}
// test.vue
<template>
  <div>
    <h2>
      mixin用法
    </h2>
    <p>
      {{name}}
    </p>
    <button @click="change">改变内容</button>
  </div>
</template>

<script>
import myMixin from './mixin';
export default {
  mixins: [myMixin], // 可以添加多个用逗号隔开,会自动合并
}
</script>

8. 动态组件和异步组件

9. 什么是MVVM

  • MVVM 是 Model-View-ViewModel的缩写
  • Model 表示数据层,用于存放数据
  • View 表示视图层,页面展示数据
  • ViewModel 用于同步 View 和 Model 之间的关联。核心是 Dom Listeners 和 Data Bindings 两个工具。Dom Listeners 用于监听 View 中 DOM 的变化,并会选择性的传递给 Model;Data Bindings 用于监听 Model数据的变化,并更新给 View。

image.png

10. 为什么Vue组件中data必须是个函数

  • 如果data是个对象,组件进行复用的时候,都会指向同一地址,造成变量污染
  • 如果data通过函数返回对象,每个对象都是一个新的对象,就不会有这一问题

11. Vue中computed和watch有什么区别

  • computed计算属性
    • 支持缓存,只有依赖的数据发生变化时才会重新计算
    • 计算属性内不支持异步操作
    • 计算属性的函数都一个get和set方法,使用计算属性进行双向数据绑定一定要使用get和set方法不然会报错
// ComputedDemo.vue
<template>
  <div>
    <!-- computed有缓存,只有关联的值发生改变才会重新计算 -->
    <p>
      double1:{{double1}}
    </p>
    <p>
      <!-- 使用计算属性,进行双向数据绑定,一定要有set和get不然会报错 -->
      <input v-model="double2">
    </p>
  </div>
</template>

<script>
export default {
  data(){
    return{
      num1: 20,
      num2: 20
    }
  },
  computed: {
    double1(){
      return this.num1 * 2;
    },
    double2: {
      get() {
        return this.num2;
      },
      set(val) {
        this.num2 = val;
      }
    }
  }
}
</script>
  • 侦听属性 watch
    • 不支持缓存,只要数据发生变化,就会执行侦听函数
    • 侦听属性内支持异步操作
    • 侦听属性的值可以是一个对象,接受handler回调,deep,immediate三个属性
<template>
  <div>
    <input type="text" v-model="name">
    <input type="text" v-model="info.city">
  </div>
</template>

<script>
export default {
  data(){
    return{
      name: "milo",
      info: {
        city: "厦门"
      }
    }
  },
  created() {
    console.log(this.name);
    this.name = "test";
  },
  watch: {
    name(oldVal, val){ // 监听原始值变量,oldVal变化前的值,val变化后的值
      console.log('watch name', oldVal, val);
    },
    info: {
      handler(oldVal, val){
        console.log('watch info', oldVal, val) // 引用值,拿不到修改前的值
      },
      deep: true, // 深度监听
      immediate: true // 首次执行也监听
    },
    'info.city': function(){ // 监听属性
      console.log(this.info.city)
    }
  }
}
</script>

12. $nextTick

Vue的响应式并不是在数据发生变化之后就立即更新DOM,vm.$nextTick是在下次Dom更新循环结束之后执行的延迟回调。在修改数据之后立即使用这个方法,获取更新后的DOM。

  • 如果你想在created内操作dom可以使用$nextTick方法

13. Vue双向数据绑定的原理

Vue采用数据劫持 + 订阅发布模式实现双向绑定。通过Object.definedProperty()来为组件中data的每个属性添加getset方法,在数据变动时,触发set里相应的监听回调函数,将变动信息发布给订阅者,订阅者重新执行render函数完成更新。

  1. 组件初始化时:
    • a. 创建一个dep对象作为观察者(依赖收集、订阅发布的载体)
    • b. 通过Object.definedProperty()方法对data中属性添加getter和setter方法;调用getter时,去dep(观察者对象)里注册函数;调用setter时,便通知刚注册的函数。
  2. 组件挂载时:
    • a. compile解析模板,将其中的变量替换成数据。然后初始化渲染页面视图,并进行dom监听和事件绑定。后续一旦数据发生变化,便会更新页面,页面发生变化也会相应发布变动信息;
    • b. 组件同时会定义watcher类作为订阅者,watcher可以视作dep和组件之间的桥梁。其在实例化时会向dep中添加自己,同时自身又有一个update方法,待收到dep变动通知时,便会调用自己的update方法,触发compile中相应的函数完成更新。

7c94a6e6ceba4ff193d3d518a3a52c7e_tplv-k3u1fbpfcp-zoom-1.png

14. Vue渲染和更新的过程

  • 渲染过程
    • 解析模板为render函数
    • 触发响应式,通过getter和setter监听data属性
    • 执行render函数,生成 vnode,然后patch(elem, vnode)生成真实的dom
  • 更新过程
    • 数据变化,触发setter
    • 重新执行render函数,生成newVnode
    • 重新patch(vnode, newVnode)
  • vue组件是异步渲染 vue在更新Dom时是异步执行的。只要侦听到数据变化,Vue将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个watcher被多次触发,只会被推入队列中一次。可以避免不必要的计算和DOM操作。

7c94a6e6ceba4ff193d3d518a3a52c7e_tplv-k3u1fbpfcp-zoom-1.png

11119410-b29172982f490ba1.webp

15.虚拟DOM的优缺点

优点:

  • 保证性能下限: 虚拟DOM可以经过diff找出最小差异,然后批量进行patch,这种操作虽然比不上手动优化,但是比起粗暴的DOM操作性能要好很多,因此虚拟DOM可以保证性能下限

  • 无需手动操作DOM: 虚拟DOM的diff和patch都是在一次更新中自动进行的,我们无需手动操作DOM,极大提高开发效率

  • 跨平台: 虚拟DOM本质上是JavaScript对象,而DOM与平台强相关,相比之下虚拟DOM可以进行更方便地跨平台操作,例如服务器渲染、移动端开发等等 缺点:

  • 无法进行极致优化: 在一些性能要求极高的应用中虚拟DOM无法进行针对性的极致优化,比如VScode采用直接手动操作DOM的方式进行极端的性能优化