🔍 Vue 响应式原理全解:Proxy、依赖追踪与视图更新是怎么协作的?
在 Vue3 中,最核心也最神奇的机制之一就是它的 响应式系统。
它可以做到:
你只管改数据,界面自动变得和你想要的一样。
但这背后的"魔法",其实主要靠 三大机制 协同工作:
✅ JavaScript Proxy
✅ 依赖追踪(依赖收集)
✅ 数据变动 → 触发视图更新
我们逐一拆开讲,最后你会发现:Vue 的响应式其实并不神秘。
1️⃣ Proxy:给数据加一个"监听器"
Vue3 用 Proxy 替代了 Vue2 的 Object.defineProperty,能对任意对象的读取和设置行为进行拦截。
👇 模拟实现:
js
const state = new Proxy({ count: 0 }, {
get(target, key) {
console.log(`读取了属性:${key}`)
return target[key]
},
set(target, key, value) {
console.log(`设置了属性:${key} = ${value}`)
target[key] = value
// 通知依赖更新视图
return true
}
})
state.count // 打印:读取了属性:count
state.count++ // 打印:设置了属性:count = 1
🧠 注释解析:
- get() 拦截访问属性,比如模板中 {{ count }};
- set() 拦截属性修改,比如执行 state.count++;
- 在这两个钩子中,Vue 会插入自己的逻辑,追踪依赖并触发更新。
🏷️ 类比一下:
把数据对象 state 想象成"仓库货架",每个属性是一个"货物"。
- get() 是你伸手去拿货,Vue 就偷偷记下"你拿了哪个货物(依赖)";
- set() 是你换了一个新货上去,Vue 就通知"所有拿过这个货的地方该更新了"。
2️⃣ 依赖追踪:谁用我,我就记住谁
每当模板或计算属性中访问响应式数据,Vue 会自动记录"谁用了这个变量"。
js
<template>
<p>{{ count }}</p>
</template>
➡️ Vue 会记录:"这个
标签使用了 count"。
✅ Vue 怎么知道是谁在访问?
因为在模板编译成渲染函数后,Vue 会在执行这些函数时设置一个全局"正在渲染谁"的标记,然后在 get() 被触发时,记录下这个依赖。
👉 比喻一下:
就像老师点名时偷偷做记录:
谁抬头听讲了,就记下来了。以后要发新通知,就通知这些认真听讲的同学。
3️⃣ 触发更新:数据一改,立刻广播
当你修改响应式数据时,例如:
js
state.count++ // 或 count.value++
Vue 会在 set() 中查找有哪些地方依赖了这个属性,并重新执行相关渲染函数或计算属性,从而触发 DOM 更新。
✅ 整个流程串起来长这样:
js
用户访问 count --> Proxy.get 拦截 --> Vue 记录依赖
用户修改 count --> Proxy.set 拦截 --> Vue 通知所有依赖:你要更新了!
- 详细的流程如下图所示:

流程说明:
-
依赖收集阶段 (读操作) :
- 用户读取
count
时触发 Proxy 的get
拦截 - Vue 将当前执行的函数(如组件渲染函数)注册为依赖
- 依赖关系存储在
Dep
依赖集合中
- 用户读取
-
更新通知阶段 (写操作) :
- 用户修改
count
时触发 Proxy 的set
拦截 - Vue 从
Dep
中获取所有关联的依赖项 - 通知所有依赖项(如组件、计算属性)执行更新
- 最终触发 UI 重新渲染或计算逻辑更新
- 用户修改
💡 关键点:Vue 3 通过 Proxy 实现细粒度依赖跟踪 ,仅在数据变化时更新相关组件,避免不必要的渲染开销。也就是我们常说的:"数据变 → 视图自动变"
这一切发生得毫无感知,你甚至不用关心"如何更新",因为 Vue 全自动完成了。
🧠 小总结:Vue 的响应式系统三部曲
原理 | 核心作用 |
---|---|
Proxy | 劫持对象属性的读写操作 |
依赖追踪 | 记录使用了哪些响应式数据 |
触发更新 | 当数据变化时,通知所有用到它的地方更新 |
🧪 深入学习建议
如果你想进一步理解 Vue 响应式系统底层的实现原理,可以参考我整理的示例源码和学习记录 👇
📦 我的 GitHub 仓库(含 Vue 响应式 DEMO):
🥳 如果你觉得这篇文章还不错...
✨ 点赞 鼓励一下作者
🧠 收藏 方便以后查阅
📣 转发 给你正在学 Vue 的朋友
💬 评论区 欢迎你来交流更多疑问和见解!