// 全局的依赖收集器Dep,相当于消息订阅器
window.Dep = class Dep {
constructor() {
this.subscribers = new Set(); // 保证依赖不重复添加
}
// 追加订阅者
depend() {
if(activeUpdate) { // activeUpdate注册为订阅者
this.subscribers.add(activeUpdate)
}
}
// 运行所有的订阅者更新方法
notify() {
this.subscribers.forEach(sub => {
sub();
})
}
}
let activeUpdate
// js单线程语言,任一时刻只能有一个函数执行,也就是任一时刻,只可能有一个依赖在更新
//用一个全局变量activeUpdate来标志
// autorun接受一个更新函数
function autorun(update) {
function wrapperUpdate() {
activeUpdate = wrapperUpdate
update() // wrapperUpdate, 闭包
activeUpdate = null;
}
wrapperUpdate();
}
function observer(obj) {
Object.keys(obj).forEach(key => {
var dep = new Dep(); // 为每个key创建订阅器Dep
let internalValue = obj[key]
Object.defineProperty(obj, key, {
get() {
// 将当前正在运行的更新函数追加进订阅者列表
if(activeUpdate) {
dep.depend() //收集依赖
}
return internalValue
},
set(newVal) {
//console.log(`setting key "${key}" to: ${internalValue}`)
// 加个if判断,数据发生变化再触发更新
if(internalValue !== newVal) {
internalValue = newVal
dep.notify() // 触发依赖的更新
}
}
})
})
}
let state = {
count:0
}
observer(state);
autorun(() => {
console.log('state.count发生变化了', state.count)
})
state.count = state.count + 5;
// state.count发生变化了 0
// state.count发生变化了 5
2021-04-12 vue订阅者模式
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- 订阅——发布模式 Vue 中使用 $on、$emit 一般用来使用兄弟组件中的参数传递,其原理就是使用了订阅发布模...