相关的文章很多,写的也很类似,这里我尝试从观察者模式的解释。动手写一写比看十边都有用。
首先举一个栗子,邮局(dep类)与邮递员(watcher类观察者),
邮递员工作,观察信来了就送信,不关心细节(data修改就更新视图)watcher.update()。
邮局工作,处理信件告知邮递员哪些信件你负责送即收集依赖到数组dep.addsub(),通知邮递员立刻马上送货,不然没工资触发依赖 dep.notify()
function observer(obj){ // 这个其实就是处理 观察者和订阅者的关系。处理邮局与邮递员的关系。
for(let [key,val] of Object.entries(obj)){
defineReactive(obj, key, val) //传入data对象,key,val
}
}
function defineReactive (obj, key, val) {
/* 一个Dep类对象 */
const dep = new Dep();
Object.defineProperty(obj, key, {
enumerable: true, /* 属性可枚举 */
configurable: true, /* 属性可被修改或删除 */
get(){
//render funtion 渲染dom的时候 肯定会用到data,所以就会触发这里get。
dep.addSub(new Watcher())
//1·收集依赖,其实就是收集(哪些信需要哪个邮递员去送信)/也就是哪个观察者订阅了哪个事件/哪个组件用了哪些data数据。
//2·访问data.a,dep实例(邮局)开始收集watcher实例(邮递员a你负责送a的信),访问data.b 就收集邮递员b,他们是分别去送不同的信。
//3·watcher也就是观察者,就是一个中间人,干活的邮递员,不需要知道细节只负责送自己负责的信就好,观察到变化就开始干活(更新视图)我只观察我负责的部分,我不需要了解细节,,
return val
},
set(){
//触发依赖过程很好理解//,
//1·dep(邮局)通知 *所有* 邮递员现在立刻去送信dep.notify(),不然不开工资。至于怎么送的过程也就是更新视图(watcher.update),邮局dep不关心。
dep.notify()
}
});
}
class Dep{
//订阅者,邮局
constructor(){
this.subs =[]
//这是一个存储队列。
}
addSub(sub){
//收集依赖,理解为 邮件很多,需要添加大量的邮递员。收集信件并告知邮递员哪些信件送到哪里。这是邮局的功能。
this.subs.push(sub)
}
notify(){
//这里就是触发依赖, 通知快递员 我这收集了好多信,那个张三的信 你可以送了,
this.subs.forEach(sub=>{
sub.update()
//这里sub就是watcher实例,埋头苦干,去快乐送信。
})
}
}
class Watcher{ //观察者,邮递员
constructor(){
}
update(){
console.log('开始送信了')
}
}
class Vue{
constructor(options){
this._data = options.data
observer(this._data);
/* 新建一个Watcher观察者对象 */
new Watcher();
/* 在这里模拟render的过程,为了触发test属性的get函数 */
console.log('render~', this._data.test);
}
}
let o = new Vue({
data:{
test:0,
}
})
o._data.test = '10件' //改动触发送信操作