vue的双向数据绑定原理,是基于订阅和发布模式的。
订阅者是使用了date数据的dom节点,发布者是vue
当创建vue实例的时候,会自动的把订阅者添加到发布者存储订阅者的数组中,
通过 Object.defineProperty对 vue中的date数据进行数据监听,数据拦截,
当vue中的data数据发生变化的时候,发布者会通过notify方法,找到订阅者的回调函数,把更新后的数据传递给订阅者,订阅者拿到更新后的数据,展示在页面当中
接下来模拟发布者和订阅者 以及添加的订阅者和通知订阅者:
// 订阅者
class Watch {
constructor(fn) {
this.fn = fn;
}
// 调用数据发生改变之后通知订阅者
callBack() {
this.fn();
}
}
// 发布者
class Dep {
constructor() {}
// 存储订阅者的名单
subs = [];
// 添加订阅者的信息
addSubs(watch) {
this.subs.push(watch);
}
// 数据发生改变之后通知订阅者
notify() {
this.subs.forEach((item) => {
item.callBack();
});
}
}
// 创建发布者
let dep = new Dep();
// 创建订阅者
let w1 = new Watch(() => {
console.log("数据发生改变");
});
// 发布者添加订阅者
dep.addSubs(w1);
// 模拟数据发生改变之后通知订阅者
dep.notify();
使用object.definePropertty()来模拟发布者和订阅者:
// 订阅者
class Watch {
constructor(fn) {
this.fn = fn;
}
// 通知订阅者
callBack() {
this.fn();
}
}
// 发布者
class Dep {
constructor() {}
// 订阅者的名单
subs = [];
// 添加订阅者
addSubs(watch) {
this.subs.push(watch);
}
// 数据发生改变之后通知订阅者
notify() {
this.subs.forEach((item) => {
item.callBack();
});
}
}
// 创建发布者
let dep = new Dep();
// 创建订阅者
let w1 = new Watch(() => console.log("数据发生改变了"));
// 发布者添加订阅者
dep.addSubs(w1);
// vue
function Observe(obj) {
if (!obj || typeof obj !== "object") return;
Object.keys(obj).forEach((key) => {
let value = obj[key];
Object.defineProperty(obj, key, {
//对当前的key值进行描述
enumerable: true,
configurable: true,
get() {
console.log("get");
return value;
},
set(v) {
console.log("set");
console.log(v);
value = v;
// 数据发生改变了 通知订阅者
dep.notify();
},
});
});
}
// 要监听的数据对象
let userObj = {
name: "小明",
age: 20,
};
// 创建vue的Observe监听数据对象
let observe = new Observe(userObj);
// 改变数据
userObj.name = "小天";