在 Vue 中,如果在运行时动态给 data 添加新的属性,Vue 无法自动追踪这个新属性的变化。这是因为 Vue 使用的是 Object.defineProperty 进行数据劫持,而 Object.defineProperty 只能在对象初始化时对已有的属性进行监听,因此动态添加的属性不会被 Vue 侦测到,也不会触发视图的更新。
发生什么?
假设你在一个组件的 data 中没有定义 newProperty,然后你想动态添加它:
this.$data.newProperty = 'newValue';
console.log(this.newProperty); // 'newValue'
在上面的例子中,你虽然可以通过 $data 访问到 newProperty,但是 Vue 无法响应它的变化,界面也不会更新。
解决办法:
Vue 提供了两种方法解决这个问题:
- 使用
Vue.set()方法:可以动态地将属性添加到响应式对象中,并确保它是响应式的。
Vue.set(this.someObject, 'newProperty', 'newValue');
this.$set()方法:与Vue.set()类似,适用于实例内的响应式数据。
this.$set(this.someObject, 'newProperty', 'newValue');
示例:
data() {
return {
person: {
name: 'John'
}
};
},
mounted() {
// 动态添加一个属性,Vue 无法追踪
this.person.age = 25;
// 正确的方式,Vue 会追踪到新属性的变化
this.$set(this.person, 'age', 25);
}
Vue 源码分析:
在 Vue 源码中,Vue 初始化响应式数据时,会通过 initData() 函数遍历 data 对象上的属性,并调用 defineReactive() 方法。这个方法使用 Object.defineProperty 将属性定义为 getter 和 setter,从而使得 Vue 可以劫持数据的读取和更新。
然而,Object.defineProperty 不能对新增的属性进行监听。这就是为什么在运行时动态添加属性不会触发响应的原因。因此,Vue 提供了 set 方法,它使用 defineReactive 手动为新增属性设置响应式劫持。
场景:
动态给 data 添加属性常见于异步请求完成后,或者组件渲染过程中,需要给对象动态添加数据时。比如,一个用户表单可能开始时只有 name 和 email 字段,但在某些交互下需要动态添加 phone 字段。
2万+

被折叠的 条评论
为什么被折叠?



