请参阅这个最小示例
App.vue
<template>
<EditPerseon :previousPerson="persons[0]" />
</template>
<script>
import EditPerseon from "./EditPerseon.vue";
export default {
data() {
return {
persons: [
{ name: "Bob", age: 18 },
{ name: "Amy", age: 20 },
],
};
},
watch: {
$data: {
handler() {
console.log("My $data have been mutated!");
},
deep: true,
},
},
components: {
EditPerseon,
},
};
</script>
EditPerseon.vue
<template>
<input v-model="currentPerson.name" />
</template>
<script>
export default {
props: {
previousPerson: Object,
},
data() {
return {
currentPerson: this.previousPerson,
};
},
};
</script>
同样在 CodeSandbox 上:
EditPerseon.vue
是我的子组件,但它仍然意外地改变了我父组件的 $data。
为什么会发生这种情况?
如何防止这种情况发生?
最佳答案
当您定义一个对象(或数组)并将其分配给 javaScript 中的另一个对象时,最终会得到对同一对象的两个引用。我想你相信你的台词:
currentPerson: this.previousPerson,
以某种方式创建一个新对象currentPerson
,该对象从this.previousPerson
复制值。然而,现在发生的情况是,现在您有两个不同的变量,它们都与原始对象链接:因此对 currentPerson
的更改实际上会修改父级的 person[0]
。
为了缓解这种情况,您可以做的一件事是在子组件中创建一个新对象:
data() {
return {
currentPerson: {...this.previousPerson},
};
},
或者:
data() {
return {
currentPerson: {
name: this.previousPerson.name
},
};
},
如果对象的某些字段本身就是对象,第一个选项将失败。第二种更安全但更冗长。您可以尝试一些像cloneDeep这样的软件包安全地克隆对象。
一个很好的通用资源,可以获取有关对象引用和副本处理的更多信息:https://javascript.info/object-copy .
除此之外,我相信观察程序处理程序总是在创建时触发,因此即使没有检测到任何更改,处理程序也会触发(但我对此 atm 不是 100% 确定)。
关于vue.js - 为什么我的 Vue 子组件一开始已经将 prop 分配给 $data,但仍然意外地改变了父 $data?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65288543/