本文主要是简单了解下vue3.0的新特性,vue2.x和vue3.0差异,以及如何使用方面进行学习,如有问题,请大佬们多多指教。
vue3.0 新特性
1.更快更省
- 压缩包体积更小
当前最小化并被压缩的vue运行时大小约为 20kB(2.6.10 版为 22.8kB)。vue3.0捆绑包的大小大约会减少一半,即大概有10kB。 - 重构
Virtual DOM
传统Virtual DOM的性能瓶颈问题,vue3.0采用动静结合减少性能损耗。 - 响应式底层从
Object.defineProperty变成ProxyObject.defineProperty是一个相对比较昂贵的操作,因为它直接操作对象的属性,颗粒度比较小,将它替换为ES6的Proxy,在目标对象之上架了一层拦截,代理的是对象而不是对象的属性,这样可以将原本对对象属性的操作变为对整个对象的操作,颗粒度变大。javascript引擎在解析的时候希望对象的结构越稳定越好,如果对象一直在变,可优化性降低,proxy不需要对原始对象做太多操作。
2.完全 TypeScript 重构
- 团队开发更轻松
- 架构更灵活,阅读源码更轻松
- 可以独立使用
Vue内部模块
将 vue2.x 中与组件逻辑相关的选项以 API 函数的形式重新设计
- 一组低侵入式的、函数式的
API - 更好的逻辑复用与代码组织
- 更好的类型推导
4.选用Function_based API
vue3.0将组件的逻辑都写在了函数内部,setup()会取代vue2.x的data()函数,返回一个对象,暴露给模板,而且只在初始化的时候调用一次,因为值可以被跟踪。
Function-based API 对比Class-based API有以下优点
- 对
typescript更加友好,typescript对函数的参数和返回值都非常好,写Function-based API既是javascript又是typescript,不需要任何的类型声明,typescript可以自己做类型推导。 - 静态的
import和export是treeshaking的前提,Function-based API中的方法都是从全局的vue中import进来的。 - 函数内部的变量名和函数名都可以被压缩为单个字母,但是对象和类的属性和方法名默认不被压缩(为了防止引用出错。
- 更灵活的逻辑复用。
5.使用了hooks
React Hook 和 Vue Hook对比
其实 React Hook 的限制非常多,比如官方文档中就专门有一个章节介绍它的限制:
1.不要在循环,条件或嵌套函数中调用 Hook
2.确保总是在你的 React 函数的最顶层调用他们。
3.遵守这条规则,你就能确保 Hook 在每一次渲染中都按照同样的顺序被调用。这让 React 能够在多次的 useState 和 useEffect 调用之间保持 hook 状态的正确。
而 Vue 带来的不同在于:
1.与 React Hooks 相同级别的逻辑组合功能,但有一些重要的区别。 与 React Hook 不同,setup 函数仅被调用一次,这在性能上比较占优。
2.对调用顺序没什么要求,每次渲染中不会反复调用 Hook 函数,产生的的 GC 压力较小。
3.不必考虑几乎总是需要 useCallback 的问题,以防止传递函数prop给子组件的引用变化,导致无必要的重新渲染。
4.React Hook 有闭包陷阱问题,如果用户忘记传递正确的依赖项数组,useEffect 和 useMemo 可能会捕获过时的变量,这不受此问题的影响。 Vue 的自动依赖关系跟踪确保观察者和计算值始终正确无误。
我们认可 React Hooks 的创造力,这也是 Vue-Composition-Api 的主要灵感来源。上面提到的问题确实存在于 React Hook 的设计中,我们注意到 Vue 的响应式模型恰好完美的解决了这些问题。
vue2.x 和 vue3.x 的Virtual DOM对比
传统Virtual DOM的性能瓶颈
数据变更之后,会触发对应Dep中的 Watcher 对象,Watcher 对象会调用对应的 update 来修改视图。这个过程主要是将新旧虚拟节点进行差异对比(新的Virtual DOM和旧的Virtual DOM进行 patch(diff算法) 算法比较,并算出二者之间的差异), 然后根据对比结果进行DOM操作来更新视图,但是传统Virtual DOM,进行算法比对时颗粒度是组件,每个组件作为一个颗粒。

虽然Vue能够保证触发更新的组件最小化,但是单个组件内部依然需要遍历该组件的整个Virtual DOM树。如下图所示,template中,只有message插值部分发生改变,整体结构不变,但是数据更新的时候,比对整个template结构,这样就存在性能损耗。

Vue3.0 Virtual DOM
动静结合:找到动态变化的部分,更新时只对比可以变化的部分,减少性能损耗。
1.节点结构不变
- 节点结构完全不会改变
只有一个动态节点

这个时候没有必要比较结构顺序。
2.节点结构变化
v-ifv-if外部:只有v-if是动态节点v-if内部:只有是动态节点
把模板切分成两个部分,各部分相对静态。
3.节点结构变化
v-forv-for外部:只有v-for是动态节点(fragment)每个
v-for循环内部:只有是动态节点
区块树Block tree
以结构性指令为边界,将整个模板切割成一个一个的相对内部静态的块。
将模板基于动态节点指令切割为嵌套的区块。
- 每个区块内部的节点结构是固定的。
- 每个区块只需要以一个Array追踪自身包含的动态节点。
响应式底层
从Object.defineProperty变成Proxy
vue2 变更检测
vue2中是递归遍历 data 中的所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter,在 getter 中做数据依赖收集处理,在 setter 中监听数据的变化,并通知订阅当前数据的地方。

这么做有什么问题呢?
- 检测不到对象属性的添加和删除:当你在对象上新加了一个属性
newProperty,当前新加的这个属性并没有加入vue检测数据更新的机制(因为是在初始化之后添加的),vue.$set是能让vue知道你添加了属性, 它会给你做处理,$set内部也是通过调用Object.defineProperty()去处理的 - 无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应。
- 性能问题,当
data中数据比较多且层级很深的时候,因为要遍历data中所有的数据并给其设置成响应式的,会导致性能下降
vue3 Proxy
Vue3 进行了全新改进,使用 Proxy代理的作为全新的变更检测,不再使用 Object.defineProperty
为什么使用 Proxy 可以解决上面的问题呢?
主要是因为Proxy是拦截对象,对对象进行一个”拦截”,外界对该对象的访问,都必须先通过这层拦截。无论访问对象的什么属性,之前定义的还是新增的,它都会走到拦截中。
下面分别用Object.defineProperty()和 Proxy 实现一个简单的数据响应
- 使用
Object.defineProperty()实现:
1 | class Observer { |
执行结果
1 | // 修改 obj原有的属性 age的输出 |
可以看到,给对象新增一个属性,内部并没有监听到,新增的属性需要手动再次使用Object.defineProperty()进行监听。
这就是为什么 vue 2.x 中 检测不到对象属性的添加和删除的原因,内部提供的$set就是通过调用Object.defineProperty()去处理的。
- 下面我们使用
Proxy替代Object.defineProperty()实现
1 | const obj = { |
1 | // 修改原对象的age属性 |
可以看到,新增的属性,并不需要重新添加响应式处理,因为 Proxy 是对对象的操作,只要你访问对象,就会走到 Proxy 的逻辑中。
Reflect(ES6引入) 是一个内置的对象,它提供拦截 JavaScript 操作的方法。将Object对象一些明显属于语言内部方法(比如Object.defineProperty())放到Reflect对象上。修改某些Object方法的返回结果,让其变得更合理。让Object操作都变成函数行为。具体内容查看MDN
vue2.x项目转换成3.x的方式
1.composition-api
Github:vuejs/composition-api安装:
1
2
3npm install @vue/composition-api
# or
yarn add @vue/composition-api前提:适合还需要使用到基于
Vue2.x的第三方插件,比如ElementUI,iview等使用:通过安装包
@vue/composition-api,然后在main.js中导入,最后使用Vue.use(xxx),就可以使用Vue3.x的语法2.vue-next
Github:vuejs/vue-next
安装:1
vue add vue-next
完全使用vue3.x的生态,包括最新版的
vue、vue-router、vuex,目前可能会找不到合适的基于Vue3.x的插件
Vue3.0和Vue2.x的差异
通过使用
composition-api方式简单的对比下
1.语法上
1 | <template> |
ref()函数接收一个参数值,返回一个响应式的数据对象。该对象只包含一个指向内部值的 .value 属性
基本用法
- 在模板中访问时,无需通过.value属性,它会自动展开
- 当 ref 作为 reactive 对象的 property 被访问或修改时,也将自动解套 value 值,其行为类似普通属性
2.生命周期钩子函数
vue3.0 中的生命周期函数和 vue2.x 相比做了一些调整和变化,对应关系如下:
beforeCreate-> 使用setup()created-> 使用setup()beforeMount->onBeforeMountmounted->onMountedbeforeUpdate->onBeforeUpdateupdated->onUpdatedbeforeDestroy->onBeforeUnmountdestroyed->onUnmountederrorCaptured->onErrorCaptured这些生命周期钩子函数只能在
setup()函数中使用,setup是位于beforeCreate和created之间调用的
参考
理解Vue3.0中的Proxy
Vue 3.0 有哪些新特性
Vue 组合式 API
Vue Function-based API RFC
Vue 3.0 全家桶抢先体验