Vue双向绑定是响应式系统、模板编译与依赖追踪协同实现的:通过Object.defineProperty(Vue 2)或Proxy(Vue 3)劫持数据,模板编译生成render函数产出VNode,Watcher在渲染时收集依赖,数据变更时异步通知更新。

Vue.js 的双向绑定不是魔法,而是响应式系统 + 模板编译 + 依赖追踪三者协同的结果。核心在于:数据变化能自动触发视图更新,用户输入又能反向更新数据,整个过程无需手动调用渲染函数。
响应式数据:Object.defineProperty 与 Proxy 的演进
Vue 2 使用 Object.defineProperty 劫持 data 对象的每个属性,为 getter/setter 注入依赖收集和派发更新逻辑。读取时(getter)将当前 Watcher 记为依赖;修改时(setter)通知所有依赖更新。
Vue 3 则基于 Proxy 重写响应式系统,可代理整个对象、支持数组索引/新增属性/删除属性等操作,不再需要 Vue.set 或 this.$set 的补丁方案。
注意:只有在 new Vue 或 setup() 中声明的初始属性才被代理,后期动态添加的普通属性不会触发更新(Vue 2 尤其明显)。
模板编译:从 HTML 字符串到可执行的 render 函数
Vue 在初始化时会把 template 编译为 render 函数(开发环境可显式配置 compiler-sfc)。例如:v-model="msg" 最终生成类似 _c('input', { on: { input: $event => msg = $event.target.value } }, [_v(msg)]) 的 VNode 描述。
这个过程包含三步:
- 解析 template 得到 AST 抽象语法树
- 静态节点标记与优化(提升 diff 效率)
- 生成可执行的 JavaScript render 函数
render 函数执行后返回虚拟 DOM(VNode),是真实 DOM 的轻量映射,也是后续 patch 的基础。
从零开始编排 SpringBoot+Vue 全栈项目工作流,适用于新建全栈项目或完整脚手架请求,触发后依次调用 product‑spec‑builder(需求调研)等模块。
依赖收集与更新派发:Watcher、Dep 与响应式链条
每个组件实例对应一个 渲染 Watcher,它在首次执行 render 函数时“碰”到响应式属性,触发其 getter,从而将自身记录进该属性对应的 Dep(依赖管理器)中。
当数据变化调用 setter 时,Dep 会遍历通知所有收集到的 Watcher,Watcher 再异步触发组件重新 render 和 patch。
关键点:
- 依赖关系是「属性 → Dep → Watcher」的树状结构,非全局广播
- 更新是异步的(nextTick),批量合并同一轮中的多次变更,避免重复渲染
- 计算属性(computed)和侦听器(watch)也基于相同机制,只是 Watcher 类型不同
v-model 的本质:语法糖背后的双向同步逻辑
v-model 并非独立功能,而是 :value + @input(或特定事件)的组合封装。 例如:
-
等价于 -
要求子组件内部触发this.$emit('input', newValue)(Vue 2)或使用 model 选项 / v-model 参数(Vue 3)
它之所以“双向”,是因为视图层输入触发事件更新数据,而数据更新又通过响应式驱动视图重绘——中间靠的是模板绑定 + 响应式系统 + 更新队列闭环。
理解这三层协作,就能明白为什么响应式数据必须初始化声明、为什么 v-for 中 key 不可省略、为什么直接赋值数组下标不会触发更新(Vue 2),以及为什么 computed 有缓存而 methods 每次执行——底层全是同一套机制在支撑。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










