问题重现
在这个示例中,通过 this.person.id = 1 直接给 person 对象添加 id 属性的方式存在一个缺陷,即这种动态添加属性的方式不会被 Vue 的响应式系统所监听。Vue 的响应式系统只能在初始化实例时对已有的属性进行监听,无法自动监听动态添加的属性。
<template>
<div>
<div>person:{{ person }}</div>
<el-button @click="change">新增一个属性:this.person.id = 1</el-button> <br />
</div>
</template>
<script>
export default {
data() {
return {
person: {
name: "oldName",
},
};
},
watch: {
person: {
handler(newValue) {
console.log(newValue);
// 输出:{id: 1, name: 'newName', get/set name}
},
deep: true, // 深度监听
},
},
methods: {
// 新增一个属性
change() {
this.person.id = 1;
this.person.name = "newName";
},
},
};
</script>
解决方案
(1)$set 或者 Vue.set() 方法:使用 Vue 提供的 $set 方法或者 Vue.set 方法来设置动态添加的属性。这样可以确保动态添加的属性也被 Vue 的响应式系统所监听,从而在属性值发生变化时能够触发相应的更新。
(2) Object.assign() 方法:使用 Object.assign() 方法也可以确保对象属性的变化被正确监听。当你使用 Object.assign() 方法将新的属性合并到对象中时,Vue.js 会检测到对象的变化并触发响应式更新。
<template>
<div>
<div>person:{{ person }}</div>
<el-button @click="change">新增一个属性:this.person.id = 1</el-button> <br />
<el-button @click="change2">新增一个属性:this.person.id2 = 2</el-button> <br />
<el-button @click="change3">新增一个属性:this.$set(this.person, "id3", 3)</el-button>
</div>
</template>
<script>
export default {
data() {
return {
person: {
name: "oldName",
},
};
},
watch: {
person: {
handler(newValue) {
console.log(newValue);
// button1 输出:{id: 1, name: 'newName', get/set name}
// button2 输出:{id2: 2, name: 'newName', get/set name, get/set id2}
// button3 输出:{id3: 3, name: 'newName', get/set name, get/set id3}
},
deep: true, // 深度监听
},
},
methods: {
// 新增一个属性
change() {
this.person.id = 1;
this.person.name = "newName";
},
change2() {
this.person.id2 = 2;
this.person.name = "newName2";
// case 1. Object.assign()
this.person = Object.assign({}, this.person);
},
change3() {
// case 2. this.$set()
this.$set(this.person, "id3", 3);
},
},
};
</script>