当前位置:首页 > VUE

vue watch 实现 原理

2026-03-28 18:32:20VUE

Vue 的 watch 实现原理

Vue 的 watch 功能用于监听数据变化并执行回调函数,其核心实现依赖于响应式系统和依赖收集机制。

初始化阶段

  1. 选项解析
    在组件初始化时,Vue 会遍历 watch 选项,为每个监听属性创建一个 Watcher 实例。
    例如:

    watch: {
      key: function(newVal, oldVal) { /* ... */ }
    }
  2. 创建 Watcher
    每个 Watcher 会记录监听的属性名(或路径)和回调函数,并标记为 user watcher(用户自定义的侦听器)。

依赖收集

  1. 首次求值
    Watcher 在初始化时会主动触发一次求值,调用 getter 函数(即监听属性的读取逻辑)。
    在读取过程中,触发属性的 get 拦截器,将当前 Watcher 添加到依赖列表(Dep 中)。

  2. 依赖关系建立
    属性通过闭包引用一个 Dep 实例,用于存储所有依赖它的 Watcher
    例如:

    vue watch 实现 原理

    // 伪代码:响应式属性的 get 拦截
    get() {
      Dep.target && dep.addSub(Dep.target); // 收集依赖
      return value;
    }

触发更新

  1. 数据变更通知
    当监听的属性被修改时,触发 set 拦截器,调用 dep.notify() 通知所有依赖的 Watcher 更新。

  2. 异步队列处理
    Watcher 的更新逻辑会被推入异步队列(通过 nextTick 实现),确保多次数据变更合并为单次回调执行。
    例如:

    // 伪代码:响应式属性的 set 拦截
    set(newVal) {
      value = newVal;
      dep.notify(); // 通知依赖更新
    }
  3. 回调执行
    最终调用用户定义的回调函数,传入新值和旧值。如果是深度监听(deep: true),会递归遍历对象属性以触发依赖收集。

    vue watch 实现 原理

深度监听的实现

  1. 递归遍历
    getter 中,如果启用 deep 选项,会递归访问对象的所有子属性,强制触发它们的 get 拦截器,从而收集深层依赖。
    例如:

    function traverse(value) {
      if (isObject(value)) {
        Object.keys(value).forEach(key => traverse(value[key]));
      }
    }
  2. 性能考虑
    深度监听可能带来性能开销,因为需要递归遍历整个对象树。Vue 3 的 watch API 通过 Proxy 优化了这一过程。

与计算属性的区别

  1. 懒执行 vs 主动执行
    计算属性(computed)是懒执行的,仅在依赖变化时重新求值;而 watch 会主动执行回调。

  2. 返回值处理
    计算属性需要返回一个值,而 watch 更适用于执行副作用(如异步操作)。

关键代码片段

Watcher 类核心逻辑

class Watcher {
  constructor(vm, expOrFn, cb, options) {
    this.vm = vm;
    this.cb = cb;
    this.deep = !!options.deep;
    this.getter = parsePath(expOrFn); // 解析属性路径
    this.value = this.get(); // 触发依赖收集
  }

  get() {
    Dep.target = this;
    let value = this.getter.call(this.vm, this.vm);
    if (this.deep) traverse(value); // 深度监听
    Dep.target = null;
    return value;
  }

  update() {
    const oldValue = this.value;
    this.value = this.get();
    this.cb.call(this.vm, this.value, oldValue); // 执行回调
  }
}

响应式属性劫持

Object.defineProperty(obj, key, {
  get() {
    if (Dep.target) dep.addSub(Dep.target);
    return value;
  },
  set(newVal) {
    if (newVal === value) return;
    value = newVal;
    dep.notify();
  }
});

标签: 原理vue
分享给朋友:

相关文章

vue实现过滤

vue实现过滤

Vue实现过滤的方法 在Vue中实现数据过滤可以通过多种方式完成,以下是几种常见的方法: 使用计算属性过滤 计算属性是Vue中处理数据过滤的理想选择,它们基于响应式依赖进行缓存,只有在相关依赖发生改…

vue compile 实现

vue compile 实现

Vue 编译实现原理 Vue 的编译过程将模板字符串转换为渲染函数,主要分为解析、优化和代码生成三个阶段。 解析阶段(Parse) 将模板字符串转换为抽象语法树(AST)。Vue 使用正则表达式和有…

vue实现翻译

vue实现翻译

Vue 实现翻译功能的方法 使用 i18n 插件实现多语言切换 安装 vue-i18n 插件: npm install vue-i18n 创建语言资源文件(如 en.json 和 zh.json):…

vue实现心电图

vue实现心电图

Vue 实现心电图效果 在 Vue 中实现心电图效果通常需要结合 Canvas 或 SVG 进行动态绘图,模拟心电图数据的实时变化。以下是两种实现方式的核心思路和代码示例: 使用 Canvas 绘制…

vue实现ide

vue实现ide

Vue 实现 IDE 的基本思路 使用 Vue 构建一个简易的集成开发环境(IDE)需要整合代码编辑器、文件管理、终端模拟等功能。以下是关键实现步骤和推荐工具。 核心功能模块 代码编辑器 使用…

vue底部实现

vue底部实现

Vue 底部实现方法 在 Vue 项目中实现底部布局可以通过多种方式完成,以下是一些常见的方法: 使用固定定位 将底部元素固定在页面底部,适用于单页应用或需要始终显示的底部栏。 <temp…