前言
本章要进入到 Watcher 类的实现了
Watcher 类
- 功能
- 当数据变化触发依赖, dep 通知所有的 Watcher实例更新视图
- 滋生实例化的时候往 dep 对象中添加自己
- 结构
-
vm 就是我们的 vue 实例
-
key就是data中的属性名称
-
cb就是一个回调函数,负责更新视图
-
oldValue 就是对应的值
-
代码
class Watcher {
constructor(vm, key, cb) {
// - vm 就是我们的 vue 实例
this.vm = vm
// - key就是data中的属性名称
this.key = key
// - cb就是一个回调函数,负责更新视图
this.cb = cb
// 把 watcher对象记录到 Dep 类的静态属性 target中
Dep.target = this
// 触发get方法,在get方法中会调用addSub
this.oldValue = vm[key]
// 防止重复添加
Dep.target = null
}
// 当数据发生变化的时候更新视图
update() {
let newValue = this.vm[this.key]
if (this.oldValue === newValue) {
return
}
this.cb(newValue)
}
}
什么时候创建 watcher 对象?
1.在插值表达式中进行更新 complier
complierText{
// 正则表达式 解析插值表达式
let reg = /\{\{(.+?)\}\}/
// 文本节点的内容
let value = node.textContent
if (reg.test(value)) {
const key = RegExp.$1.trim()
node.textContent = value.replace(reg, this.vm[key])
// 创建 watcher 类, 当数据改变更新视图
new Watcher(this.vm, key, (newValue) => {
node.textContent = newValue
})
}
}
- 在指令中进行更新 complier
update(node, key, attrName) {
let updateFn = this[`${attrName}Updater`]
// 为什么需要这样进行修改呢?
// 1. 首先我们在使用 textUpdater 或 modelUpdater时候 并非 this.xxx 如此调用
// 2. 如果是 this.xxx 调用的话,那么他的this指向就是 我们的 compiler
// 3. 我们回忆一下 函数的调用时的this指向会,是由他的调用式形式所决定的
// 4. 我们现在这样调用,他的this指向就不是我们所需要的 compiler 对象
updateFn && updateFn.call(this, node, this.vm[key], key)
}
// 处理 v-text 指令
textUpdater(node, value, key) {
node.textContent = value
// 创建 watcher 类, 当数据改变更新视图
new Watcher(this.vm, key, (newValue) => {
node.textContent = newValue
})
}
// v-model
modelUpdater(node, value, key) {
node.value = value
// 创建 watcher 类, 当数据改变更新视图
new Watcher(this.vm, key, (newValue) => {
node.value = newValue
})
}