vue框架之 Watcher 类

666 阅读1分钟

前言

本章要进入到 Watcher 类的实现了

Watcher 类

image.png

  • 功能
    • 当数据变化触发依赖, dep 通知所有的 Watcher实例更新视图
    • 滋生实例化的时候往 dep 对象中添加自己
  • 结构

image.png

  • 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
      })
    }
}
  1. 在指令中进行更新 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
    })
  }