关于Vue的双向绑定

360 阅读1分钟
  1. 需要一个数据对象: data,他需要被处理响应: observe(data, true /* asRootData */)

  2. observe 做了啥?(数组的先放一边)

    • 通过new Observer(value) 进行处理,他有一个管家Dep,同时有个小工this.walk(value)
  // 小工开始干活
  walk (obj: Object) {
    const keys = Object.keys(obj)
    for (let i = 0; i < keys.length; i++) {
      defineReactive(obj, keys[i])
    }
  }
  1. defineReactive做了啥? 为每个对象的key 分配一个管家dep,并监听对象的get 和 set行为。再set的时候,通过dep发出更新通知,get的时候,收集需要通知的对象(依赖收集)

  2. 如何依赖收集?

在对象的Set方法中看到如下代码:

    get: function reactiveGetter () {
      const value = getter ? getter.call(obj) : val
      **// 这个判断是啥鬼东西?**
      if (Dep.target) {
        **// 这行代码又是啥?**
        dep.depend()
        // 子ob也要和当前watcher建立关系
        if (childOb) {
          childOb.dep.depend()
          if (Array.isArray(value)) {
            dependArray(value)
          }
        }
      }
      return value
    }
  • 看源码从而得到的答案: Dep.target是管家类的定义对象,默认为null
    depend() 方法是 是管家的方法

那需要了解Dep.target何时赋值?其次depend()做了,我们基本就能明白依赖的收集。

  • Dep.target何时赋值: 管家类有个方法:
export function pushTarget (target: ?Watcher) {
  targetStack.push(target)
  Dep.target = target
}

它何时被调用了,那么回到Vue的初始方法那边,初始化数据对象后,需要干嘛?需要挂载DOM元素。

所以去挂载处理里面需要答案。

$mount => mountComponent => updateComponent赋值(render函数执行)=> new Watcher() => 依赖收集 => render执行

一个组件,一个Watcher

  get () {
    // 管家与Watcher依赖收集
    pushTarget(this)
    const vm = this.vm
    value = this.getter.call(vm, vm)
    popTarget()
    this.cleanupDeps()
    return value
  }

这时 Dep.target 就被赋值了,然后调用Dom的渲染函数时,相关的数据被调用是,就会触发下方的判断,并建立关系:

    get: function reactiveGetter () {
      const value = getter ? getter.call(obj) : val
      **// 这时watcher
      if (Dep.target) {
        **// 这行代码又是啥?**
        dep.depend()
        // 子ob也要和当前watcher建立关系
        if (childOb) {
          childOb.dep.depend()
          if (Array.isArray(value)) {
            dependArray(value)
          }
        }
      }
      return value
    }

就是当Watcher对象存在时,就在 数据的管家中 记录关联组件的Watcher对象。包含数据的子对象也要记录关联。当这个数据被变换时, 就从通过dep管家通知相关的Watcher。

  1. 总结

image.png

image.png