面试官:说说Vue2和Vue3的区别

208 阅读4分钟

一. 根节点不同

  1. vue2中必须要有根标签
  2. vue3中可以没有根标签,会默认将多个根标签包裹在一个fragement虚拟标签中,有利于减少内存。

二. 组合式API和选项式API

  1. 在vue2中采用选项式API,将数据和函数集中起来处理,将功能点切割了当逻辑复杂的时候不利于代码阅读。
  2. 在vue3中采用组合式API,将同一个功能的代码集中起来处理,使得代码更加有序,有利于代码的书写和维护。

三. 生命周期对比

vue2vue3描述
beforeCreatesetup()创建前
createdsetup()创建后
beforeMountonBeforeMount挂载前
mountedonMounted挂载后
beforeUpdateonBeforeUpdate更新前
updatedonUpdated更新后
beforeDestroyedonBeforeUnmount销毁前
destroyedonUnmounted销毁后
errorCapturedonErrorCaptured异常捕获
activatedonActivated被激活(包含在<keep-alive>中的组件,被激活时执行)
deactivatedonDeactivated切换(比如从A组件切换到B组件,A组件消失时执行)

四. v-if和v-for的优先级

  1. 在vue2中v-for的优先级高于v-if,可以放在一起使用,但是不建议这么做,会带来性能上的浪费
  2. 在vue3中v-if的优先级高于v-for,一起使用会报错。可以通过在外部添加一个标签,将v-for移到外层

五. diff算法不同

  1. vue2中的diff算法

    • 遍历每一个虚拟节点,进行虚拟节点对比,并返回一个patch对象,用来存储两个节点不同的地方。
    • 用patch记录的消息去更新dom
    • 缺点:比较每一个节点,而对于一些不参与更新的元素,进行比较是有点消耗性能的。
    • 特点:特别要提一下Vue的patch是即时的,并不是打包所有修改最后一起操作DOM,也就是在vue中边记录变更新。(React则是将更新放入队列后集中处理)。
  2. vue3中的diff算法

    • 在初始化的时候会给每一个虚拟节点添加一个patchFlags,是一种优化的标识。
    • 只会比较patchFlags发生变化的节点,进行识图更新。而对于patchFlags没有变化的元素作静态标记,在渲染的时候直接复用。

六.响应式原理不同

  1. vue2通过Object.definedProperty()的get()和set()来做数据劫持、结合和发布订阅者模式来实现,Object.definedProperty()会遍历每一个属性。
  2. vue3通过proxy代理的方式实现(注意:vue3并不是完全的抛弃了defineProperty,通过reactive定义的响应式数据使用proxy包装出来,而ref还是用的defineProperty去给一个空对象,定义了一个value属性来做的响应式。)。
  3. proxy的优势:
    • defineProperty只能监听某个属性,不能对全对象进行监听;
    • 可以省去for in 、闭包等内容来提升效率(直接绑定整个对象即可);
    • 可以监听数组,不用再去单独的对数组做特异性操作,vue3可以检测到数组内部数据的变化。

七.插槽方式不同

  1. 在vue2中

匿名插槽

子组件:
<div>
	<slot></slot>
</div>

父组件:
<child>
  <span>我是插槽插入的内容</span>
</child>

具名插槽

子组件:
<div>
  <slot name="person"></slot>
</div>

父组件:
<child>
  <span slot="person">我是插槽插入的内容</span>
</child>

作用域插槽:父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。不过,我们可以在父组件中使用slot-scope 特性从子组件获取数据

<div>
  <slot :data="data"></slot>
</div>
父组件:
<child>
  <span slot-scope="data">我是插槽插入的内容</span>
</child>

2.在vue3中

匿名插槽:和vue2一样

具名插槽

子组件:
<div>
  <slot name="person"></slot>
</div>
父组件:
<child>
  <template v-slot:person>
    <span>我是插槽插入的内容</span>
  </template>
</child>

作用域插槽

子组件:
<div>
  <slot :data="data"></slot>
</div>
父组件:
<child>
  <span #data>我是插槽插入的内容</span>  === <span #default="{data}">我是插槽插入的内容</span>
</child>

  1. 总结
  • 具名插槽使用方式不同:vue2使用slot='',vue3使用v-slot:''
  • 作用域插槽使用方式不同:vue2中在父组件中使用slot-scope="data"从子组件获取数据,vue3中在父组件中使用 #data 或者 #default="{data}"获取

八.样式穿透

  1. 在vue2中
/deep/ .类名{}
::v-deep .类名{}

2.在vue3中

:deep (.类名{})
::v-deep(.类名{})

九.一些细节区别

  • 因为改成了组合式api所以没有了this
  • 一些全局注册,比如mixin,注册全局组件,use改成了用app实例调用,而不是vue类调用
  • 新增了传送门teleport组件
  • 组合式api的写法下,源码改成了函数式编程,方便按需引入,因为tree-shaking功能必须配合按需引入写法。所以vue3更好的配合tree-shaking能让打包体积更小。
  • 性能优化,增加了静态节点标记。会标记静态节点,不对静态节点进行比对。从而增加效率。
  • vue3不推荐使用mixin进行复用逻辑提取,而是推荐使用hook
  • v-model应用于组件时,监听的时间和传递的值改变:vue2中组件中传递一个value,监听 change/input事件;vue3通过modelValue传递值,监听的是update:modelValue事件
  • ts更好的配合