"别再更新了,实在是学不动了"这句话道出了多少前端开发者的心声,"不幸"的是 Vue 的作者在国庆区间发布了 Vue3.0 的 pre-Aplha 版本,这意味着 Vue3.0 快要和我们见面了。既来之则安之,扶我起来我要开始讲了。Vue3.0 为了达到更快、更小、更易于维护、更贴近原生、对开发者更友好的目的,在很多方面进行了重构:
使用 Typescript
放弃 class 采用 function-based API
重构 complier
重构 virtual DOM
新的响应式机制
今天咱就聊聊重构后的响应式数据。
尝鲜
重构后的 Vue3.0 和之前在写法上有很大的差别,早前在网络上对于 Vue3.0 这种激进式的重构方式发起了一场讨论,见仁见智。不多说先看看 Vue3.0 在写法上激进到什么程度。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="https://www.jb51.net/packages/vue/dist/vue.global.js"></script> </head> <body> <div></div> <script> const { reactive, computed, effect, createApp } = Vue const App = { template: ` <div> <button @click="add">{{ state.count }}</button> </div> `, setup() { const state = reactive({ count: 0 }) function add() { state.count++ } effect(() => { console.log('count改变', state.count); }) return { state, add } } } createApp().mount(App, '#app') </script> </body> </html>
确实写法上和 Vue2.x 差别有点大,还整出了个 setup。不过我的第一感觉倒不是写法上的差异,毕竟写过 React,这种写法也没啥特别的。关键是这种响应式数据的写法好像在哪里见过有没有?写过 React 项目的人可能一眼就能看出来,没错就是它 mobx,一种 React 的响应式状态管理插件
import {observable,computed,autorun} from "mobx" var numbers = observable([1,2,3]); var sum = computed(() => numbers.reduce((a, b) => a + b, 0)); var disposer = autorun(() => console.log(sum.get())); // 输出 '6' numbers.push(4); // 输出 '10' numbers.push(5);
再看看 Vue3.0 暴露的这几个和响应式数据相关的方法:
reactive(value)
创建可观察的变量,参数可以是 JS 原始类型、引用、纯对象、类实例、数组、集合(Map|Set)。
effect(fn)
effect 意思是副作用,此方法默认会先执行一次。如果 fn 中有依赖的可观察属性变化时,会再次触发此回调函数
computed(()=>expression)
创建一个计算值,computed 实现也是基于 effect 来实现的,特点是 computed 中的函数不会立即执行,多次取值是有缓存机制的,expression 不应该有任何副作用,而仅仅是返回一个值。当这个 expression 依赖的可观察属性变化时,这个表达式会重新计算。
和 mobx 有异曲同工之妙。
Vue3.0 把创建响应式对象从组件实例初始化中抽离了出来,通过暴露 API 的方式将响应式对象创建的权利交给开发者,开发者可以自由的决定何时何地创建响应式对象,就冲这点 Vue3.0 我先粉了。
重构后的响应式机制带来了哪些改变?
每一个大版本的发布都意味着新功能、新特性的出现,那么重构后的响应式数据部分相比 3.0 之前的版本有了哪些方面的改变呢?下面听我娓娓道来:
对数组的全面监听
Vue2.x 中被大家吐槽的最多的一点就是针对数组只实现了 push,pop,shift,unshift,splice,sort,reverse' 这七个方法的监听,以前通过数组下标改变值的时候,是不能触发视图更新的。这里插一个题外话,很多人认为 Vue2.x 中数组不能实现全方位监听是 Object.defineProperty 不能监听数组下标的改变,这可就冤枉人家了,人家也能侦听数组下标变化的好吗,不信你看
const arr = ["2019","云","栖","音","乐","节"]; arr.forEach((val,index)=>{ Object.defineProperty(arr,index,{ set(newVal){ console.log("赋值"); }, get(){ console.log("取值"); return val; } }) }) let index = arr[1]; //取值 arr[0] = "2050"; //赋值
没毛病,一切变化都在人家的掌握中。上面这段代码,有没有人没看懂,我假装你们都不懂,贴张图
从数组的数据结构来看,数组也是一个 Key-Value 的键值对集合,只是 Key 是数字罢了,自然也可以通过Object.defineProperty 来实现数组的下标访问和赋值拦截了。其实 Vue2.x 没有实现数组的全方位监听主要有两方面原因: