当前位置:首页 > VUE

vue实现依赖收集

2026-03-28 15:36:50VUE

Vue 依赖收集的实现原理

Vue 的依赖收集主要通过响应式系统完成,核心涉及 ObserverDepWatcher 三个类。以下是具体实现方式:

响应式数据初始化

通过 Object.definePropertyProxy 对数据对象进行劫持,拦截属性的读取和修改操作。Vue 2.x 使用前者,Vue 3.x 使用后者。

vue实现依赖收集

// Vue 2.x 的 defineProperty 实现
function defineReactive(obj, key, val) {
  const dep = new Dep() // 每个属性对应一个 Dep 实例

  Object.defineProperty(obj, key, {
    get() {
      if (Dep.target) { // 当前 Watcher 存在时收集依赖
        dep.depend()
      }
      return val
    },
    set(newVal) {
      if (newVal === val) return
      val = newVal
      dep.notify() // 数据变化时通知更新
    }
  })
}

Dep 依赖管理器

Dep 类负责管理一组 Watcher,实现依赖的添加和通知。

class Dep {
  constructor() {
    this.subs = [] // 存储 Watcher 实例
  }

  depend() {
    if (Dep.target) {
      Dep.target.addDep(this) // Watcher 记录 Dep
    }
  }

  notify() {
    const subs = this.subs.slice()
    for (let i = 0; i < subs.length; i++) {
      subs[i].update() // 触发 Watcher 更新
    }
  }
}
Dep.target = null // 静态属性指向当前 Watcher

Watcher 观察者

Watcher 实例在初始化时会触发 getter 函数,从而触发依赖收集。

vue实现依赖收集

class Watcher {
  constructor(vm, expOrFn, cb) {
    this.vm = vm
    this.getter = parsePath(expOrFn)
    this.cb = cb
    this.value = this.get()
  }

  get() {
    Dep.target = this // 设置当前 Watcher
    const value = this.getter.call(this.vm, this.vm) // 触发 getter
    Dep.target = null // 收集完成后清除
    return value
  }

  addDep(dep) {
    dep.addSub(this) // Dep 记录 Watcher
  }

  update() {
    // 触发组件更新或回调
    this.run()
  }
}

依赖收集流程

  1. 组件渲染时创建 Watcher 实例,触发 get() 方法
  2. Dep.target 被设置为当前 Watcher
  3. 访问数据属性时触发 getter,调用 dep.depend()
  4. Watcher 记录所有关联的 Dep,同时 Dep 记录 Watcher
  5. 数据变更时通过 dep.notify() 通知所有关联 Watcher 更新

Vue 3 的改进

Vue 3 改用 Proxy 实现响应式,依赖收集原理类似但更高效:

const reactive = (target) => {
  return new Proxy(target, {
    get(target, key, receiver) {
      track(target, key) // 依赖收集
      return Reflect.get(target, key, receiver)
    },
    set(target, key, value, receiver) {
      Reflect.set(target, key, value, receiver)
      trigger(target, key) // 触发更新
    }
  })
}

关键区别在于:

  • 无需递归遍历对象属性
  • 可自动检测新增/删除属性
  • 性能更好,尤其对大型对象

标签: vue
分享给朋友:

相关文章

vue实现冰墩墩

vue实现冰墩墩

使用 Vue 实现冰墩墩动画 通过 Vue 的动画特性和 SVG 技术,可以动态渲染冰墩墩的形象。以下是具体实现方法: 准备 SVG 素材 冰墩墩的形象通常由多个 SVG 路径组成,包括身体轮廓、面…

vue实现123456

vue实现123456

Vue 实现数字 123456 的显示 在 Vue 中显示数字 123456 非常简单,可以通过以下方法实现: 方法一:直接在模板中显示 <template> <div>…

vue实现首页

vue实现首页

Vue 实现首页的基本步骤 安装 Vue.js 和相关依赖,可以通过 Vue CLI 或 Vite 快速初始化项目。Vue CLI 适合传统项目,Vite 更适合现代前端开发。 npm instal…

vue实现侧导航

vue实现侧导航

Vue 实现侧边导航 使用 Vue 实现侧边导航可以通过多种方式完成,以下是一种常见的实现方法,结合 Vue Router 和动态组件。 基础结构 创建侧边导航栏的基本结构,通常使用 <ul&…

vue打包实现推送

vue打包实现推送

Vue 项目打包与自动化部署推送 打包 Vue 项目 使用以下命令生成生产环境代码,默认输出到 dist 目录: npm run build 配置自动化推送(以 GitHub Pages 为例)…

vue实现按钮弹窗

vue实现按钮弹窗

实现按钮弹窗的基本方法 在Vue中实现按钮点击触发弹窗功能,可以通过多种方式完成。以下是几种常见实现方法: 使用原生HTML和Vue指令 通过v-if或v-show控制弹窗显示状态,结合点击事件切换…