一、创建 Observer.js
import Dep from "./dep.js";
export default class Observer {
constructor(data) {
this.walk(data);
}
walk(data) {
Object.keys(data).forEach((key) => {
defineReactive(data, key, data[key]);
});
}
}
function defineReactive(obj, key, val) {
const dep = new Dep();
Object.defineProperty(obj, key, {
get() {
if (window.target) {
dep.depend();
}
return val;
},
set(newVal) {
if (newVal === val) return;
val = newVal;
dep.notify();
},
});
}
二、创建Dep.js
export default class Dep {
constructor() {
this.subs = []; //收集wacher
}
depend() {
if (window.target) {
this.subs.push(window.target);
}
}
notify() {
this.subs.forEach((sub) => sub.update());
}
}
三、创建Watcher
export default class Watcher {
constructor(vm, expOrFn, cb) {
this.vm = vm;
this.getter = parsePath(expOrFn);
this.cb = cb;
this.value = this.get();
}
get() {
window.target = this;
let value = this.getter.call(this.vm, this.vm);
window.target = undefined;
return value;
}
update() {
const oldValue = this.value;
this.value = this.get();
this.cb.call(this.vm, this.value, oldValue);
}
}
function parsePath(path) {
const segments = path.split(".");
return function (obj) {
for (let i = 0; i < segments.length; i++) {
if (!obj) return;
obj = obj[segments[i]];
}
return obj;
};
}
四、在index.js 中调用
import Observer from "./Observer";
import Watcher from "./watcher.js";
const vm = {
data: {
messsage: {
name: "hello",
},
},
};
new Observer(vm.data);
new Watcher(vm, "data.messsage.name", (value, oldValue) => {
console.log(value, oldValue);
});
vm.data.messsage.name = "world";
首先看一下下面的图
创建一个vm 使用Observer遍历vm的每一项 使用Object.defineProperty 劫持数据 并且new 了一个dep此时并没有依赖收集 下面我们去new 一个watcher 类似一个中介 watcher 内部触发getter方法的时候 会触发defineProperty中的get 并且我们把当前的watcher 挂载到window.target上所以dep内部会把一个一个的watcher存在sub中 watcher 基本上分为三大类 渲染watcher 计算属性watcher 监听watcher