想必大多数人都被defineProperty的机制坑过,所以在Vue3.0即将到来之际,我做了一个Vue3.0与2.x的响应式效果的比对。没有对比就没有伤害,对比之后才会知道3.0用了Proxy之后有多么强大。
打包
从Vue3.0源码仓库 clone一份源码。
安装
npm i
打包
npm run build
发现出错了,ts的类型检查有问题,更新一下 source-map
npm i source-map
继续打包,发现又出错,还是ts的类型错误,在transformExpression.ts这个文件中,把报错的类型全部声明为any(反正我们只是为了打包),继续打包
这次打包成功了,生成的文件在packages/vue/dist目录下,共有7个文件:
- vue.cjs.js
- vue.cjs.prod.js
- vue.esm-browser.js
- vue.esm-browser.prod.js
- vue.esm-bundler.js
- vue.global.js
- vue.global.prod.js
我们选择vue.global.prod.js,可以在浏览器中直接使用
准备示例代码
创建文件
- 使用IDEA(WebStorm也一样)创建一个空的项目
- 新建static文件夹(个人习惯)
- 在static文件夹下加入刚刚打包的Vue3.0的js文件以及Vue2的js文件
- 在static文件夹下分别创建Vue2.x和Vue3.x的测试文件 Vue2.x: index2.html, vue2.js Vue3.0: index3.html, vue3.js
- 创建一个可用于展示响应式特性的组件文件comp.js
这个时候,static下的文件结构是这样的:
- comp.js
- index2.html
- index3.html
- vue.global.prod.js
- vue.js
- vue2.js
- vue3.js
准备测试代码
编写html文件
index2.html内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app"></div>
<script src="./comp.js"></script>
<script src="./vue2.js"></script>
</body>
</html>
index3.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./vue.global.prod.js"></script>
</head>
<body>
<div id="app"></div>
<script src="./comp.js"></script>
<script src="./vue3.js"></script>
</body>
</html>
除了引用文件的不同没有任何其他的区别
编写公共组件
const Comp = {
template: `
<div>
<h2>测试对象添加属性</h2>
<div>{{person}}</div>
<div>
<button @click="addProperty">添加属性</button>
<button @click="deleteProperty">删除属性age</button>
</div>
<h2>测试数组修改</h2>
<div>{{array}}</div>
<div>
<button @click="addArrayItemProperty">添加元素0属性</button>
<button @click="deleteArrayItemProperty">删除元素0属性</button>
<button @click="replaceArrayItem">替换元素1</button>
</div>
</div>
`,
data() {
return {
msg: 'abc',
person: { name: 'aa', age: 22 },
array: [{
name: '1'
}, {
name: '2'
}]
};
},
methods: {
addProperty() {
this.msg = this.msg + '1';
this.person[this.msg] = this.msg;
},
deleteProperty() {
delete this.person.age;
},
addArrayItemProperty() {
this.array[0].enname = 'abc';
},
deleteArrayItemProperty() {
delete this.array[0].name;
},
replaceArrayItem() {
this.array[1] = { name: '222' };
}
}
};
组件内的操作分别验证的是:
- 对象属性添加
- 对象属性删除
- 对象数组内已存在元素的属性添加
- 对象数组内已存在元素的属性删除
- 对象数组内已存在元素的替换(使用索引)
这里有个小插曲,一开始我只是验证3.0的响应式,所以编写组件的时候template没有用div包裹,直接声明了多个根节点(也是无心插柳,毕竟很少直接写浏览器渲染的组件),本来没发现问题,结果同样的组件用在2.x上的时候,提示我组件不能存在多个根节点...
编写Vue3.0与2.x的入口文件
vue2.js
new Vue({
el: '#app',
template: '<Comp/>',
components: {
Comp: Comp
}
});
vue3.js
const app = Vue.createApp();
app.mount(Comp, '#app');
事实显示Vue3.0的入口编写更为简便,不过这不是今天的主题,接下来就是见证的时刻:
在IDE中直接运行index2.html和index3.html
是不是一毛一样?这里发现一个小问题,Vue2.x渲染出来的内容,并排的button之间有间隙,而Vue3.0渲染的内容没有。我审查元素发现两个页面的源码是一毛一样的。这个如果有人知道为什么的话请告诉我一下。
接下来我们依次点击两个页面上的5个按钮后看页面的变化:
2.x
点完之后,海棠依旧,没有任何的变化
3.0
内容发生变化,5个操作全部生效
结束语
这次的验证到这里就结束了,这次的验证一方面是想尽快尝试一下3.0的使用(等发布不知道还要多久,估计还得几个月,核心代码还在开发,配套的工具估计在开发完之后还要一段时间),另外我写了一个Vue的表单解决方案(没有在掘金发布过,只在公司内部使用),踩过defineProperty的不少坑,所以可能会提前开发适配3.0的版本。OK,让我们共同期待Vue3.0的正式发布吧!