Vue源码分析-响应式原理总结

465 阅读1分钟

前面三篇文章都分析了响应式原理的实现,本篇会简单总结一下, 之后一起看一个有意思的例子

  • Observer 建立数据劫持
  • Dep 收集依赖,通知更新
  • Watcher 提供update 接口,触发render 的调用,render的调用过程中一步一步的收集依赖,建立 Dep 和 Watcher的依赖关系

关系图

Vue2.0.png

任何依赖的收集过程都凭借对应的更新函数:

render watcher 和 所依赖的 data 靠 render 函数的执行
computed watcher 和 所依赖的 data 靠 computed handler 的执行
user watcher 和所依赖的data 靠 watch handler 的执行

这里有个特殊的数组类型的数据,特殊点在于通过重写Array原型上的7个方法进行处理,但归根结底就是遍历数组元素,对每个元素走observe 的逻辑。 。

pop, push, shift, unshift, reverse, sort, splice

看个🌰

<template>
  <section>
   <div v-for="item in list" :key="item.id">
      {{ item.name }} : {{ item.value}}
    </div>
     <div v-for="item in list2" :key="item">
      {{ item }}
    </div>
    <button @click="handleChangeListData" name="button">changeListData </button>
  </section>
</template>

<script>
export default {
  name: 'demo',
  data() {
    return {
      list: [
        {
          id: 1,
          name: 'first',
          value: 1,
        },
        {
          id: 2,
          name: 'second',
          value: 2,
        },
        {
          id: 3,
          name: 'third',
          value: 3,
        }
      ],
      list2: [1,2,3,4]
    }
  },
  methods: {
    handleChangeListData() {
      // this.list[2].name = 'aaaa'
      this.list2[2] = 'aaaa'
    },
  }
}
</script>

点击按钮,页面并未发生任何变化。

换种方式,如果我们放开handleChangeListData方法内的第一句的注释看下效果:

image.png

显然页面更新了,什么原理呢,list 类型为 Array<obj>, 收集list依赖时,遍历list, 对于 object 类型的数据,在收集依赖的时候,去建立了render wacther 和 objDep 的关系,所以我直接调用list[2].name = 'aaaa',可以触发对应dep 的notify, 最终造成render 函数的重新渲染,也就解释了为什么list2 的数据也变成了最新的,list2[2] 虽然未触发render,但list[2].name 'aaaa' 触发了,就是被捎带着执行了。