vue2
基于Object.defineProperty()实现
vue3 基于Proxy
proxy与Object.defineProperty(obj, prop, desc)方式相比有以下优势:
- 丢掉麻烦的备份数据
- 省去for in 循环
- 可以监听数组变化
- 代码更简化
Vue2 这个对数组并不友好所以vue2 没有绑定数组
let data={name: ' peak ' ,age: 10} 参数一:劫持的对象 //参数二:劫持的属性 I //参数三:给属性添加的set, get方法 Object.defineProperty(data,'name ' ,{ get: ()=>{console.log('访问了name属性');, set: (newvalue)=>{data[name]=newvalue;console.log('设置了name属性')} }) console.log(100) data.name=20
看一段类似于vue2的源码
class Observer { constructor(data) { this._data = data this.walk(this._data) } walk(data) { Object.keys(data).forEach(key => { this.defineReactive(data, key, data[key]) }) } defineReactive(data, key, value) { if (value.constructor.name === "Object") { this.walk(value) } console.log(value) Object.defineProperty(data, key, { get() { return value }, set(newVal) { value = newVal } }) } }
Vue3 proxy省去了for in 并且支持绑定数组
var obj = {}; var obj1 = new Proxy(obj, { // target就是第一个参数obj, receive就是返回的obj(返回的proxy对象) get: function (target, key, receive) { // 返回该属性值 return target[key]; }, set: function (target, key, newVal, receive) { // 执行赋值操作 target[key] = newVal; document.getElementById('text').innerHTML = target[key]; } })
Vue3 优化Vdom
patch flag 优化静态树
当我们创建了一个动态的 dom 元素:
<span>Hello world!</span> <span>Hello world!</span> <span>Hello world!</span> <span>Hello world!</span> <span>{{msg}}/span> <span>Hello world!</span> <span>Hello world! </span>
Vue3 编译后的 Vdom 是这个样子的:
export function render(_ctx,_cache,$props,$setup,$data,$options){return (_openBlock(),_createBlock(_Fragment,null,[ _createvNode( "span", null,"Hello world ! "), _createvNode( "span",null,"Hello world! "), _createvNode( "span",null,"Hello world! "), _createvNode( "span", null,"Hello world! "), _createVNode("span", null,_toDisplaystring(_ctx.msg),1/* TEXT */), _createvNode( "span", null,"Hello world! "), _createvNode( "span", null,"Hello world! ")],64/*STABLE_FRAGMENT */))
新增了 patch flag 标记
TEXT = 1 // 动态文本节点 CLASS=1<<1,1 // 2//动态class STYLE=1<<2,// 4 //动态style PROPS=1<<3,// 8 //动态属性,但不包含类名和样式 FULLPR0PS=1<<4,// 16 //具有动态key属性,当key改变时,需要进行完整的diff比较。 HYDRATE_ EVENTS = 1 << 5,// 32 //带有监听事件的节点 STABLE FRAGMENT = 1 << 6, // 64 //一个不会改变子节点顺序的fragment KEYED_ FRAGMENT = 1 << 7, // 128 //带有key属性的fragment 或部分子字节有key UNKEYED FRAGMENT = 1<< 8, // 256 //子节点没有key 的fragment NEED PATCH = 1 << 9, // 512 //一个节点只会进行非props比较 DYNAMIC_SLOTS = 1 << 10 // 1024 // 动态slot HOISTED = -1 // 静态节点 BALL = -2
我们发现创建动态 dom 元素的时候,Vdom 除了模拟出来了它的基本信息之外,还给它加了一个标记: 1 /* TEXT */
这个标记就叫做 patch flag(补丁标记)
patch flag 的强大之处在于,当你的 diff 算法走到 _createBlock 函数的时候,会忽略所有的静态节点,只对有标记的动态节点进行对比,而且在多层的嵌套下依然有效。
尽管 JavaScript 做 Vdom 的对比已经非常的快,但是 patch flag 的出现还是让 Vue3 的 Vdom 的性能得到了很大的提升,尤其是在针对大组件的时候。
Vue3 Fragment
上一篇文章讲过了可以同时支持多个根节点
<template> <div>12</div> <div>23</div> </template>
还有一个就是支持jsx
render
render() { return ( <> {this.visable ? ( <div>{this.obj.name}</div> ) : ( <div>{this.obj.price}</div> )} <input v-model={this.val}></input> {[1, 2, 3].map((v) => { return <div>{v}-----</div>; })} </> ); },
Vue3 Tree shaking
简单来讲,就是在保持代码运行结果不变的前提下,去除无用的代码
在Vue2中,无论我们使用什么功能,它们最终都会出现在生产代码中。主要原因是Vue实例在项目中是单例的,捆绑程序无法检测到该对象的哪些属性在代码中被使用到
而Vue3源码引入tree shaking特性,将全局 API 进行分块。如果你不使用其某些功能,它们将不会包含在你的基础包中
就是比如你要用watch 就是import {watch} from 'vue' 其他的computed 没用到就不会给你打包减少体积
Vue 3 Composition Api
也就是 Setup 上一篇文章已经讲完了