赞
踩
class Dep {
constructor () {
this.subs = []
}
// 收集观察者
addSub (watcher) {
this.subs.push(watcher)
}
// 通知观察者去更新
notify () {
this.subs.forEach(w => w.update())
}
}
class Watcher { constructor (vm, expr, cb) { this.vm = vm this.expr = expr this.cb = cb // 先把旧值保存起来 this.oldVal = this.getOldVal() } getOldVal () { Dep.target = this // 在定义watcher时在Dep类上增加属性target指向自身watcher const oldVal = compileUtil.getVal(this.expr, this.vm) // 获取数据时就在属性自身的dep上把该watcher添加上去 Dep.target = null // 不设置为null的话每次获取数据就会一直往对应的dep中加入watcher(这时的watcher看此时Dep的target的指向),数据更改后就会执行该dep中的所有watcher的update() return oldVal } update () { const newVal = compileUtil.getVal(this.expr, this.vm) if(newVal !== this.oldVal) { // 值改变才去更新 this.cb(newVal) // 调用cb函数处理视图 this.oldVal = newVal // 把watcher的旧值改为新值 } } }
new Vue()
然后new Observer()
然后new Compile()
new Observer()
时创建属性各自的dep
new Compile()
中new Watcher()
,执行new Watcher()
时:会先绑定Dep
类上的target
为这个new Watcher()
,接着执行,需要获取数据getOldVal()
,就会执行这里的get()
,这样子就顺利把每个属性的watcher
添加到各自的dep
中了dep.notify()
即可class Observer { ... defineReactive (obj, key, value) { this.observe(value) // 如果是对象的话就会继续递归监听 const dep = new Dep() // 定义该属性自身的dep Object.defineProperty(obj, key, { enumerable: true, configurable: false, get () { Dep.target && dep.addSub(Dep.target) // 顺序是这样的,先new Vue()然后new Observer()然后new Compile() // 在new Compile()中new Watcher(),执行new Watcher()时:会先绑定Dep类上的target为这个new Watcher(),接着执行,需要获取数据getOldVal(),就会执行这里的get(),这样子就顺利把每个属性的watcher添加到各自的dep中了 return value }, set: (newVal) => { // 使用普通函数的话this指向obj if(newVal !== value) { this.observe(newVal) // 对新值也要进行监听 value = newVal } dep.notify() // 当数据变动时通知自身的dep } }) } }
new Compile()
的过程中new Watcher()
中把watcher
添加到属性自身的dep
dep
去执行watcher.update()
修改compileUtil
:
v-html
中增加watcher
const compileUtil = {
html (node, expr, vm) {
const value = this.getVal(expr, vm)
new Watcher(vm, expr, (newVal) => { // 当数据变化时执行该回调函数修改对应的视图
this.updater.htmlUpdater(node, newVal)
})
this.updater.htmlUpdater(node, value)
},
}
v-model
中增加watcher
:const compileUtil = {
model (node, expr, vm) {
const value = this.getVal(expr, vm)
// 绑定更新函数,数据=>视图
new Watcher(vm, expr, (newVal) => { // 当数据变化时执行该回调函数修改对应的视图
this.updater.modelUpdater(node, newVal)
})
this.updater.modelUpdater(node, value)
},
}
v-text
以及普通文本的修改:const compileUtil = { text (node, expr, vm) { let value let reg = /\{\{(.+?)\}\}/g if(reg.test(expr)) { // 处理文本 value = expr.replace(reg, (...args) => { // 普通文本中可能有多个{{}}插值,因此要匹配出来逐一增加`watcher` new Watcher(vm, args[1], () => { this.updater.textUpdater(node, this.getContentVal(expr, vm)) }) return this.getVal(args[1], vm) }) } else { value = this.getVal(expr, vm) // 处理v-text new Watcher(vm, expr, (newVal) => { this.updater.textUpdater(node, newVal) }) } this.updater.textUpdater(node, value) }, ... getContentVal (expr, vm) { return expr.replace(/\{\{(.+?)\}\}/g, (...args) => { return this.getVal(args[1], vm) }) }, }
至此,我们就实现了数据=>视图的功能了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。