当前位置:首页 > 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单文件组件构建基础结构: <templat…

vue实现增删

vue实现增删

Vue 实现增删功能 在 Vue 中实现增删功能通常涉及数据绑定、事件处理和列表渲染。以下是基于 Vue 2 或 Vue 3 的实现方法: 数据定义 初始化一个数组用于存储列表数据,并在 Vue 实…

vue实现兼容

vue实现兼容

Vue 兼容性实现方案 Vue.js 的兼容性主要涉及对不同浏览器、Vue 版本以及第三方库的支持。以下是常见的兼容性解决方案: 浏览器兼容性 使用 Babel 转换 ES6+ 代码为 ES5 语…

vue实现导航

vue实现导航

使用 Vue Router 实现导航 Vue Router 是 Vue.js 官方提供的路由管理器,用于构建单页应用(SPA)的导航系统。以下是实现导航的基本步骤。 安装 Vue Router n…

vue实现数据渲染

vue实现数据渲染

Vue 数据渲染的实现方式 Vue.js 提供了多种数据渲染的方式,包括插值表达式、指令和计算属性等。以下是常见的实现方法: 插值表达式 使用双大括号 {{ }} 将数据绑定到模板中,数据变化时会自…

vue实现回顶部

vue实现回顶部

实现方法一:使用 window.scrollTo 在Vue组件中,可以通过调用 window.scrollTo 方法平滑滚动到页面顶部。该方法接受一个配置对象,指定滚动行为为平滑(smooth)。…