之前更新的时候讲过vue的响应式原理,今天来写一些重要的内容.
订阅者 Dep
订阅者dep是用来收集依赖和通知依赖更新的类,每一个相应式数据都有一个对应的dep实例,他有方法dep.add将依赖收集进dep数组,当数据发送改变时可以通过dep.notify去通知依赖更新.
class Dep {
constructor () {
this.deps = []; // 用来存储全部的依赖watcher
}
// 收集依赖
addDep = (watcher) => {
this.deps.push(watcher);
console.log('收集依赖的列表', this.deps);
};
// 通知依赖
notify = (params) => {
console.log('params', params);
this.deps.forEach((item) => {
item.update(params); // 通过watch中的update,通知页面更新
});
};
}
发布者 Observe
Observe类有个方法就是definereactive函数,遍历递归data数据,给每一个属性添加getter和setter属性,使其变成响应式数据
class Observer {
constructor (data) {
this.walk(data)
}
// 1. 判断数据是否是对象,如果不是对象返回
// 2. 如果是对象,遍历对象的所有属性,设置为 getter/setter
walk (data) {
if (!data || typeof data != 'object') {
return
}
Object.keys(data).forEach(key => {
this.defineReactive(data, key, data[key])
})
}
// 定义响应式成员 即对data总的数据实现setter和getter
defineReactive (data, key, val) {
const that = this
// 如果 val 是对象,继续设置它下面的成员为响应式数据
// this.walk(val)
Object.defineProperty(obj, 'age', {
get () {
console.log('watcher', watcher);
dep.addDep(watcher); // 收集依赖
return val; // return的值不能直接object.age,会溢出
},
set (val) {
console.log('set调取');
dep.notify(val);
}
});
}
}
观察者 Watcher
Vue 中定义一个 Watcher 类来表示观察订阅依赖。我们在响应式数据可能在很多地方用到,比如模板,或者一个watch,那么我们每一次用到的地方就要生成这个数据的一个watcher的实例记录相关的依赖,当数据改变的时候我们通知这些watcher去更新视图.
//属性全部的依赖就是watcher
class Watcher {
constructor (id) {
this.id = id;
}
update = (value) => {
console.log('数据改变了,通知我要更新', value);
document.getElementById('text').innerText = value;
}
}
测试
let obj = {
name: 'nihao',
age: 18
};
let watcher = new Watcher('1'); // 实例化一个watcher
let dep = new Dep(); //实例化一个dep
new Observer(obj)
obj.age = 23; // 改变age,会调取set方法
document.getElementById('app').addEventListener('click', () => {
obj.age = (Math.random() * 20).toFixed();
});