Reactivity响应式简单实现

7/23/2022 vue

最简单的响应式主要只包含三个元素:ObserverDepWatcher

  • Observer:递归地监听对象上的所有属性,在属性值改变的时候,触发相应的watcher
  • Watcher:观察者,当监听的数据值修改时,执行响应的回调函数(Vue里面的更新模板内容)
  • Dep:连接ObserverWatcher的桥梁,每一个Observer对应一个Dep,它内部维护一个数组,保存与该Observer相关的Watcher
function Observer(target, key, value) {
  let dep = new Dep()
  if (Object.prototype.toString.call(value) == '[object Object]') Reflect.ownKeys(value).forEach(key => new Observer(value, key, value[key]))
  Object.defineProperty(target, key, {
    enumerable: true,
    configurable: false,
    get() {
      Dep.target && dep.addSub(Dep.target) // 订阅
      return value
    },
    set(newVal) {
      dep.notify() // 通知 
      value = newVal
    }
  })
}
class Dep {
  constructor() {
    this.subs = [] // watchers数组
  }
  addSub(watcher) {
    !this.subs.includes(watcher) && this.subs.push(watcher) // 避免重复收集
  }
  notify() {
    this.subs.forEach(watcher => watcher.update())
  }
}
class Watcher { // 观察者模式
  constructor(renderCb) {
    this.renderCb = renderCb
  }
  update() {
    Dep.target = this
    this.renderCb()
    Dep.target = null
  }
}

官方原理图如下 image.png

// 测试
let app = document.getElementById('app')
let vm = {
  data: {
    id: 1007,
    goods: { price:1 }
  }
}
let ob = new Observer(vm, 'data', vm.data)
let watcher = new Watcher(() => app.innerHTML = vm.data.goods.price)
watcher.update()

let btn = document.getElementById('btn')
btn.onclick = () => vm.data.goods.price++

对照测试示例如下 image.png

    要么重构,
    要么享受!
    红莲华
    x
    loading...