一. 根节点不同
- vue2中
必须要有根标签 - vue3中
可以没有根标签,会默认将多个根标签包裹在一个fragement虚拟标签中,有利于减少内存。
二. 组合式API和选项式API
- 在vue2中
采用选项式API,将数据和函数集中起来处理,将功能点切割了当逻辑复杂的时候不利于代码阅读。 - 在vue3中
采用组合式API,将同一个功能的代码集中起来处理,使得代码更加有序,有利于代码的书写和维护。
三. 生命周期对比
| vue2 | vue3 | 描述 |
|---|---|---|
| beforeCreate | setup() | 创建前 |
| created | setup() | 创建后 |
| beforeMount | onBeforeMount | 挂载前 |
| mounted | onMounted | 挂载后 |
| beforeUpdate | onBeforeUpdate | 更新前 |
| updated | onUpdated | 更新后 |
| beforeDestroyed | onBeforeUnmount | 销毁前 |
| destroyed | onUnmounted | 销毁后 |
| errorCaptured | onErrorCaptured | 异常捕获 |
| activated | onActivated | 被激活(包含在<keep-alive>中的组件,被激活时执行) |
| deactivated | onDeactivated | 切换(比如从A组件切换到B组件,A组件消失时执行) |
四. v-if和v-for的优先级
在vue2中v-for的优先级高于v-if,可以放在一起使用,但是不建议这么做,会带来性能上的浪费在vue3中v-if的优先级高于v-for,一起使用会报错。可以通过在外部添加一个标签,将v-for移到外层
五. diff算法不同
-
vue2中的diff算法
- 遍历每一个虚拟节点,进行虚拟节点对比,并返回一个patch对象,用来存储两个节点不同的地方。
- 用patch记录的消息去更新dom
- 缺点:比较每一个节点,而对于一些不参与更新的元素,进行比较是有点消耗性能的。
- 特点:特别要提一下Vue的patch是即时的,并不是打包所有修改最后一起操作DOM,也就是在vue中边记录变更新。(React则是将更新放入队列后集中处理)。
-
vue3中的diff算法
- 在初始化的时候会给每一个虚拟节点添加一个patchFlags,是一种优化的标识。
- 只会比较patchFlags发生变化的节点,进行识图更新。而对于patchFlags没有变化的元素作静态标记,在渲染的时候直接复用。
六.响应式原理不同
- vue2通过Object.definedProperty()的get()和set()来做数据劫持、结合和发布订阅者模式来实现,Object.definedProperty()会遍历每一个属性。
- vue3通过proxy代理的方式实现(
注意:vue3并不是完全的抛弃了defineProperty,通过reactive定义的响应式数据使用proxy包装出来,而ref还是用的defineProperty去给一个空对象,定义了一个value属性来做的响应式。)。 - proxy的优势:
- defineProperty只能监听某个属性,不能对全对象进行监听;
- 可以省去for in 、闭包等内容来提升效率(直接绑定整个对象即可);
- 可以监听数组,不用再去单独的对数组做特异性操作,vue3可以检测到数组内部数据的变化。
七.插槽方式不同
- 在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>
- 总结
具名插槽使用方式不同:vue2使用slot='',vue3使用v-slot:''作用域插槽使用方式不同:vue2中在父组件中使用slot-scope="data"从子组件获取数据,vue3中在父组件中使用 #data 或者 #default="{data}"获取
八.样式穿透
- 在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更好的配合