Vue3
# Vue3.0
# vue3.0
相对于vue2.x
有什么更新特别重要
监测机制的改动:基于
proxy
的observer
的实现,消除了Vue2.x
的Object.defineProperty
的实现所存在的很多限制(对于数组的深层监听无法实现,都是将data
里面的数据进行defineProperty
进行绑定,后加的属性不会被绑定)只监测属性,不监测对象
- 监测属性的添加和删除
- 监测数组的索引和长度的变更
- 支持
map
set
weakmap
weakset
生命周期
- 使用
setup
代替了原来的beforeCreate
和created
- 使用
模板
3.0
版本将作用域插槽改成函数的形式,这样只会影响子组件的重新渲染,提升性能对象式组件声明方式
vue2.x
通过声明形式传入option
,和ts
的结合需要通过装饰器,3.0
改成类式的写法,和ts
更方便结合
其他
支持自定义渲染
支持
fragment
(多根节点)和portal
组件基于
tree shaking
# proxy
和defineProperty
区别特别重要
Vue2.x
在实例初始化的时候遍历data
对象中所有的属性,利用Object.defineProperty
将这些属性转换成getter/setter
,当数据发生变化自动触发setter
defineProperty
是es5
无法使用polyfill
的特性,所以不支持ie8
以下
但是defineProperty
缺点
无法监测添加和删除对象的属性,因为没有初始化的时候添加
getter/setter
,只能通过$set
进行处理无法监测到数组下标和长度的变化
采用proxy
来监测数据的变化,proxy
是es6
的功能,有以下优点
proxy
可以直接代理整个对象而非对象属性,只需做一层代理就可以监听同级一下所有属性的变化,包括新增属性和删除属性proxy
可以监听数组的变化
# proxy
在vue
中的工作原理
get
依赖收集set
delete
触发依赖对于集合类型,就是在集合对象做一层包装:原方法执行后执行依赖相关的收集或者触发逻辑
# Proxy
只会代理对象的第一层,那么Vue3
又是怎样处理这个问题的呢?特别重要
判断当前Reflect.get的
返回值是否为Object
,如果是则再通过reactive
方法做代理, 这样就实现了深度观测。
# 监测数组的时候可能触发多次get/set
,那么如何防止触发多次呢?特别重要
我们可以判断key
是否为当前被代理对象target
自身属性,也可以判断旧值与新值是否相等,只有满足以上两个条件之一时,才有可能执行trigger
// 模拟 Vue 中的 data 选项
let data = {
msg: 'hello',
count: 0
}
// 模拟 Vue 实例
let vm = new Proxy(data, {
// 当访问 vm 的成员会执行
get (target, key) {
console.log('get, key: ', key, target[key])
return target[key]
},
// 当设置 vm 的成员会执行
set (target, key, newValue) {
console.log('set, key: ', key, newValue)
if (target[key] === newValue) {
return
}
target[key] = newValue
document.querySelector('#app').textContent = target[key]
}
})
// 测试
vm.msg = 'Hello World'
console.log(vm.msg)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Proxy
相比于 defineProperty
的优势
- 数组变化也能监听到
- 不需要深度遍历监听
Proxy
是ES6
中新增的功能,可以用来自定义对象中的操作
let p = new Proxy(target, handler);
// `target` 代表需要添加代理的对象
// `handler` 用来自定义对象中的操作
// 可以很方便的使用 Proxy 来实现一个数据绑定和监听
let onWatch = (obj, setBind, getLogger) => {
let handler = {
get(target, property, receiver) {
getLogger(target, property)
return Reflect.get(target, property, receiver);
},
set(target, property, value, receiver) {
setBind(value);
return Reflect.set(target, property, value);
}
};
return new Proxy(obj, handler);
};
let obj = { a: 1 }
let value
let p = onWatch(obj, (v) => {
value = v
}, (target, property) => {
console.log(`Get '${property}' = ${target[property]}`);
})
p.a = 2 // bind `value` to `2`
p.a // -> Get 'a' = 2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28