vue3相比于vue2有了明显的性能提升,而最直接的就是从Object.defineProperty换成了proxy做数据劫持,而effect是响应式系统的核心,响应式系统又是vue3中的核心。
最基本的响应式就是我改变一个值,另一个值也自动做出变化。
此时我们执行一下文件会看到达到了我们想要的目的。当然这并不是我们最终想要的,我们看一下vue3是如何做的。
在vue3中reactivity可以作为一个单独的模块下载。
effect函数执行了两次,在第一次传入匿名函数的时候执行了一次 在之后a变量的值发生变化的时候又执行了一次。
现在我们自己来实现一个响应式系统。
响应式最重要的就是收集依赖和触发依赖。
1.创建一个类用来收集和触发依赖
2.在声明变量时触发收集操作
这时候就和vue3中的ref很像了。现在可以优化一下。将在收集依赖时手动调用depend方法改为在get方法中调用,在变量重新赋值时手动调用notice方法改为在set中调用。
3.创建一个reactive函数,return一个Proxy对象
在Proxy中使用get来拦截取值行为并return出对应结果。这里我们使用的是ES6新的Reflect函数。相关文档点击这里,总之Reflect.get(target,key)相当于target[key]。
4.创建全局map用于存储所有的对象与依赖关系
5.设置set方法拦截赋值行为并触发依赖
6.使用effectWatch方法保存依赖
这就完成了一个基本的reactive方法,实现了响应式关系。
全部代码:
// let a = 10;
// let b;
// update()
// function update() {
// b = a + 10;
// console.log(b)
// }
// a = 20;
// update();
// vue3的reactivity模块
// const { reactive, effect } = require("@vue/reactivity");
// let a = reactive({
// value: 10,
// });
// let b;
// effect(() => {
// b = a.value + 10;
// console.log(b);
// });
// a.value = 20;
// 响应式库
let currentEffect; // 全局依赖
class Dep {
constructor(val) {
this.effects = new Set(); // 依赖列表
this._val = val;
}
get value() {
this.depend();
return this._val;
}
set value(newVal) {
this._val = newVal
this.notice()
}
// 收集依赖
depend() {
if (currentEffect) this.effects.add(currentEffect)
}
// 触发依赖
notice() {
this.effects.forEach((effect) => {
effect()
})
}
}
// 收集依赖
function effectWatch(effect) {
currentEffect = effect;
// 绑定依赖时先触发一次依赖
effect();
currentEffect = null;
}
// const dep = new Dep(10)
// let b;
// effectWatch(() => {
// b = dep.value + 10;
// console.log(b)
// })
// dep.value = 20;
// vue3 proxy
const targetMap = new Map(); // 存储所有的依赖映射关系
function getDepta(target, key) {
let depsMap = targetMap.get(target) // 获取对象的所有依赖
if (!depsMap) {
depsMap = new Map()
targetMap.set(target, depsMap)
}
let dep = depsMap.get(key) // 获取对应key的所有依赖
if (!dep) {
dep = new Dep();
depsMap.set(key, dep)
}
return dep;
}
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
const dep = getDepta(target, key);
dep.depend() // 收集依赖
return Reflect.get(target, key)
},
set(target, key, value) {
const dep = getDepta(target, key);
const relust = Reflect.set(target, key, value)
// 触发依赖
dep.notice();
return relust;
}
})
}
const user = reactive({
age: 19,
aaa: 30
})
let b, c;
effectWatch(() => {
console.log('reactive')
b = user.age + 10
console.log(b)
})
effectWatch(() => {
console.log('reactive1111')
c = user.aaa - 5
console.log(c)
})
user.age = 20
user.aaa = 20
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。