结合源码深入理解Vue双向绑定手写双向绑定

182 阅读2分钟

2021-06-06记录:

vue响应式原理的基本流程: 初始化Vue实例时,Observer遍历data里所有属性,使用Object.defineProperty()方法把这些属性都转为getter/setter。并且创建dep管理器(一个属性一个Dep,用来管理该属性下的所有Watcher,如果同一个属性在DOM节点中多次使用会创建多个Watcher)

在解析指令时,创建Watcher,将更新函数放到Watcher的回调上。

初始化视图时,会读取属性值,触发get,将创建的Watcher添加到dep中。

当修改数据时,触发set,调用dep的notify,通知该dep内部所有Watcher的执行回调,重新render当前组件,生成新的虚拟DOM树。

Vue框架会遍历并对比新虚拟DOM树和旧虚拟DOM树种每个节点的差别,并记录下来,最后,加载操作,将所有记录的不同点,局部修改到真DOM树上。

Object.defineProperty()方法大家都知道,用来监测一个对象的值,通过getter和setter属性进行劫持属性的操作和更新

    const data = {
        name: '',
      }
      // 拷贝一下data对象 防止死循环
      let newData = { ...data }
      Object.defineProperty(data, 'name', {
        get: () => {
          console.log('读取')
          return newData.name
        },
        set: (newval) => {
          console.log('设置')
          newData.name = newval
          response()
        },
      })
      setTimeout(() => {
        data.name = 'hello world'
      }, 1000)
      //输入时为data重新赋值 通知监听的方法为newData更改数据来达到页面新数据的动态呈现
      iptName.oninput = function () {
        data.name = this.value
      }
      const response = () => {
        hName.innerText = data.name
        iptName.value = data.name
      }
      
      //简单实现一个Object.defineProperty()

创建Observer 递归监控劫持数据

现在开始考虑我们上面的data有多个属性,我们就需要一个方法或者类去遍历这个对象

  //先为Object.defineProperty()封装一个公共的方法 并简化方法里面的操作
 function defineReactive(data, key, value = data[key]) {
 observe(value)//监听子属性
  Object.defineProperty(data, key, {
        get() {
          return value
        },
        set(newValue) {
          value = newValue
          
        }
      })
    }
创建Observe函数去递归实现数据劫持
const observer =(data) => {
    Object.keys(data).forEach((k) => defineReactive(data, k))
}

const data = {a:1,b:{c:1}}
observer(data)

订阅者Dep和模板解析指令Compile

Compile不太好理解 继续看源码 待更新