Vue响应式依赖“读取收集+修改通知”路径:data需初始化属性,未声明属性不响应;依赖仅在模板/计算属性等读取时收集;setter触发更新,数组索引赋值等会绕过响应式。

Vue 响应式数据的追踪不是“自动感知变化”,而是靠一套明确的触发路径:读取时收集依赖,修改时通知更新。理解这条路径,才能避开常见坑,比如新增属性不更新、数组索引赋值无效、对象深层属性没反应等。
响应式起点:data 属性必须初始化
Vue 在实例创建时,只对 data 对象上已存在的属性 进行劫持(Vue 2 用 Object.defineProperty,Vue 3 用 Proxy)。未声明的属性不会进入响应式系统。
- ✅ 正确:在 data 中预先定义
user: { name: '', age: 0 },后续改this.user.name = 'Alice'会触发更新 - ❌ 错误:直接
this.user.avatar = 'a.png',该属性不可响应;同理this.newField = 'xxx'也不会触发视图刷新 - ✅ 补救方式:Vue 2 用
this.$set(this.user, 'avatar', 'a.png');Vue 3 可用reactive()配合proxy天然支持动态添加,但ref()包裹的对象仍需用proxy或reactive()替代原始对象
依赖收集:发生在“读取”那一刻
模板渲染、计算属性、watch 的 getter 执行过程,就是依赖被收集的过程。只有真正被访问到的属性,才会和当前 watcher 关联。
递归分析 Vue 项目组件依赖,从入口文件生成组件层级图,支持 Vue 2/3,输出组件名、文件路径和属性。适用于分析组件结构、排查依赖或了解项目架构。
- 例如模板中写了
{{ user.profile.bio }},那么user→profile→bio这条链路上每个属性的 getter 都会被触发,各自对应的 Dep 就会把当前渲染 watcher 记下来 - 如果某段逻辑从未执行(比如条件未满足的
v-if分支),其中的属性就不会被收集,后续改了也不会触发它更新 - 计算属性的 getter 同样遵循此规则:只收集它实际读取的响应式字段,不读的不会建立依赖
派发更新:setter 触发通知,但仅限“可劫持”的变更
响应式更新不是监听“变量变了”,而是监听“响应式属性的 setter 被调用”。因此,某些写法看似改了数据,实则绕过了 setter。
立即学习“前端免费学习笔记(深入)”;
- ✅ 有效更新:
this.list.push(item)(Vue 已重写数组方法)、this.obj.count++、this.$set(this.obj, 'newKey', val) - ❌ 无效更新:
this.list[0] = newItem(数组索引直接赋值,Vue 2 不拦截)、this.obj['newKey'] = val(非响应式添加)、Object.assign(this.obj, { a: 1 })(批量赋值不触发 setter) - ⚠️ 注意:Vue 3 的 Proxy 默认能拦截
obj.newKey = val,但仅限于 reactive() 创建的对象;ref() 的 .value 赋值仍走 setter,所以安全
调试关键:确认是否进了 track / trigger 流程
遇到不更新,先验证两个环节是否走通:
- 打开浏览器控制台,在组件中执行
this.$log()(Vue 2)或使用 Vue Devtools 查看响应式对象结构,确认目标属性旁有小锁图标或__ob__: Observer标记 - 在修改数据前后加
console.log,确认代码确实执行;再检查该属性是否在依赖收集阶段被读取过(比如是否在模板里用了、是否在 computed 中引用了) - 用
watch监听目标字段,若 handler 没触发,说明 setter 没走通或根本没进响应式系统

















