《Vue设计与实现》第四章 设计一个响应设系统
- 我们使用 Proxy 进行数据代理,在 get / set 中分别进行响应式数据依赖收集 / 或者触发
- 我们需要建立一系列的关系,使其在修改相应的数据时,对应的函数能及时触发执行。
let bucket = new WeakMap();
- 我们创建了一个 WeakMap(),将来我们会往里面添加一系列数据。
- 但是往里面添加数据,要符合一定的数据结构。
好,现在让我们来编写代码
let activeFffect;
let bucket = new WeakMap();
let data = { name:'我是一个名字', ok: true }
let obj = new Proxy(data, {
get(target, value) {
// 在获取中
if (!activeFffect) return target[key];
// 获取使用 target 获取对应的new Map()桶
let depsMap = bucket.get(target);
if (!depsMap) {
// 如果没有,就需要重新设置
bucket.set(target, (depsMap = new Map()))
}
// 使用 key,对应的属性来获取,对应的 new Set()桶
let deps = depsMap.get(key);
if (!deps) {
// 如何没有,就需要重新设置
depsMap.set(key, (deps = new Set()))
}
// 好了,现在我们就要往里面添加对应的副作用函数了
deps.add(activeFffect); // 添加到 deps桶里
return target[key];
},
// 在设置中
set (target, key, value) {
target[key] = value;
// 1.根据taget从bucket桶中获取对应的数据
let depsMap = bucket.get(target);
if (!depsMap) {
// 如果没有,就之间退出
return;
}
// 根据key来获取,对应的 new Set()桶
let deps = depsMap.get(key);
deps && deps.forEach(item => item());
// 全部遍历出来,然后全部执行。
}
})
// 好了,核心的代码已经完成了
let effect = (fn) => {
activeFffect = fn;
fn();
}
effect(() => {
document.body.innerHTML = obj.name;
})
- 在fn()函数执行时,因为有 obj.name 读取操作,就会触发 get() 拦截器。然后会根据,obj , name初始化一系列的数据结构。
- 并且会将 fn 函数添加到 name 对应的 new Set()桶中。
第二次修改
obj.name = '哈哈哈,我被修改了'
在第二次修改中,会触发 set () 函数,导致 name 对应的 new Set()桶中的函数全部执行。
最终的效果就是
document.body.innerHTML = "哈哈哈,我被修改了";