⚡ 30 秒速记

  • Vue 2 属性访问器拦截已有字段
  • 渲染读取时,依赖记录关联当前观察者
  • 写入通知相关观察者,再安排刷新
  • 更新会重新收集实际使用的依赖
  • 新属性与数组索引修改存在特别边界

Vue 2 响应式像给属性装上读写门铃:渲染读到它时登记依赖,值变化时通知需要更新的工作。 属性通过访问器包裹,观察者执行渲染时完成登记,写入再触发通知与调度,最后生成新界面并更新节点。关键不只是检测赋值,还要知道谁用过这个值。新增字段和某些数组操作绕不过既有访问器的限制,要使用该版本提供的更新方式。

版本校准: 本文出现 Object.defineProperty、Dep、Watcher 和双端 Diff 时,主要描述 Vue 2 实现;Vue 3 使用 Proxy、effect 与新的渲染器路径。Vue 2 已于 2023-12-31 结束维护,新项目应以 Vue 3 为基线,旧项目参考 Vue 2 EOL 官方说明 制定迁移与安全策略。

# Vue 初始化

先从最简单的一段 Vue 代码开始:

<template>
  <div>
    {{ message }}
  </div>
</template>
<script>
new Vue({
  data() {
    return {
      message: "hello world",
    };
  },
});
</script>
  • 这段代码很简单,最终会在页面上打印一个 hello world,它是如何实现的呢?
  • 我们从源头:new Vue 的地方开始分析。
// 执行 new Vue 时会依次执行以下方法
// 1. Vue.prototype._init(option)
// 2. initState(vm)
// 3. observe(vm._data)
// 4. new Observer(data)

// 5. 调用 walk 方法,遍历 data 中的每一个属性,监听数据的变化。
function walk(obj) {
  const keys = Object.keys(obj);
  for (let i = 0; i < keys.length; i++) {
    defineReactive(obj, keys[i]);
  }
}

// 6. 执行 defineProperty 监听数据读取和设置。
function defineReactive(obj, key, val) {
  // 为每个属性创建 Dep(依赖搜集的容器,后文会讲)
  const dep = new Dep();
  // 绑定 get、set
  Object.defineProperty(obj, key, {
    get() {
      const value = val;
      // 如果有 target 标识,则进行依赖搜集
      if (Dep.target) {
        dep.depend();
      }
      return value;
    },
    set(newVal) {
      val = newVal;
      // 修改数据时,通知页面重新渲染
      dep.notify();
    },
  });
}
webapp
公众号
开发者导航
切换夜间模式
点击侧边栏上一篇
点击侧边栏下一篇
折叠侧边栏
收起全部