介绍四种角色
Observer
数据劫持,vue2使用Obeject.defineProperty()监听数据变化,vue3使用ES6的proxy构造函数监听数据变化,为每个属性分配一个订阅者集合的管理数组Dep,添加方式不限于:v-model,v-bing,{{}},等用到该属性的指令,修改属性值则触发set()方法,在set()方法内通知订阅者数组Dep,订阅者数组循环调用自身的update()方法更新视图
Dep
存放订阅者,有addWatcher()和notice()方法,当Dep收到来自Observer的数据变化,调用notice()方法通知给Watcher
Watcher
订阅者,有update()方法,收到Dep的通知后,会调用自身的update()方法,并触发Compile中绑定的回调
Compiler
解析模板指令,更新视图
代码实现
class Dep {
constructor() {
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
notify() {
this.subs.forEach((sub) => sub.update());
}
}
class Observer {
constructor(obj) {
Object.keys(obj).forEach((key) => {
let internalValue = obj[key];
const dep = new Dep();
Object.defineProperty(obj, key, {
get() {
if (Dep.target) {
dep.addSub(Dep.target);
}
return internalValue;
},
set(newVal) {
if (internalValue === newVal) return;
internalValue = newVal;
dep.notify();
},
});
});
return obj;
}
}
class Watcher {
constructor(name) {
this.name = name;
Dep.target = this;
this.update();
Dep.target = null;
}
update() {
console.log(this.name + "更新");
}
}
const state = {
name: "test",
};
new Observer(state);
const dep = new Dep();
const w1 = new Watcher("订阅者1");
dep.addSub(w1);
const w2 = new Watcher("订阅者2");
dep.addSub(w2);
state.name = "pre";