Vue3.0与Vue2.0的响应式对比

2,320

想必大多数人都被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,可以在浏览器中直接使用

准备示例代码

创建文件

  1. 使用IDEA(WebStorm也一样)创建一个空的项目
  2. 新建static文件夹(个人习惯)
  3. 在static文件夹下加入刚刚打包的Vue3.0的js文件以及Vue2的js文件
  4. 在static文件夹下分别创建Vue2.x和Vue3.x的测试文件 Vue2.x: index2.html, vue2.js Vue3.0: index3.html, vue3.js
  5. 创建一个可用于展示响应式特性的组件文件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的正式发布吧!