我理解这个概念:孩子在自己的道具数据副本上工作,并且在更改后可以$emit
进行更改,以便父级可以自行更新。
但是,我正在处理一个递归树结构,例如一个文件系统,是一个很好的类比。
[
{ type: 'dir', name: 'music', children: [
{ type: 'dir', name: 'genres', children: [
{ type: 'dir', name: 'triphop', children: [
{ type: 'file', name: 'Portishead' },
...
]},
]}
]}
]}
我有一个名为Thing
的递归组件,它使用childtree
prop 并看起来像这样:
<template>
<input v-model="tree.name" />
<thing v-for="childtree in tree.children" :tree="childtree" ></thing>
</template>
修改名称显然会直接修改道具,这是可以避免的,Vue会发出警告。
但是,我唯一能避免的方法是让每个组件都对childtree
进行深层复制。然后$emit
份我们的副本,并@input
(或类似的副本)将其复制回原件;一直到树上,这将改变树下的道具,导致所有事物的另一个深层复制!
这感觉像在任何大小的树上都效率很低。
有更好的方法吗?我知道您可以欺骗Vue不发出错误/警告example jsfiddle。
答案 0 :(得分:1)
解决您的问题是从子组件传递公正事件。 https://jsfiddle.net/kv1w72pg/2/
<input @input="(e) => $emit('input', e.target.value)" />
话虽如此,我强烈建议您使用其他解决方案,例如:
这将使代码清晰并确保真理的一种来源。
编辑:在递归继承的情况下,使用提供注入会更容易:https://jsfiddle.net/s0b9fpr8/4/
通过这种方式,您提供了可以将基本组件的状态更改为所有子组件的函数(必须注入函数)。
答案 1 :(得分:0)
单向数据流
每次更新父组件时,子组件中的所有道具都会以最新值刷新。这意味着您不应该尝试在子组件内部变异道具。如果这样做,Vue将在控制台中警告您。
请注意,JavaScript中的对象和数组是通过引用传递的,因此 如果prop是数组或对象,则使对象或数组本身发生突变 子组件中的元素会影响父状态。
以下是lodash
的示例当我们clone
时。
var objects = [{ 'a': 1 }, { 'b': 2 }];
var shallow = _.clone(objects);
console.log(shallow[0] === objects[0]);
// => true
当我们使用cloneDeep
var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false
因此,如果要更新子组件中的任何props值,则需要使用lodash的cloneDeep
。
答案 2 :(得分:0)
大致是我的处理方式:
<template>
<div>
<input v-model="myName" @input="updateParent()" />
<thing v-for="(child, i) in myChildren" :key="child.uniqueId"
@input="setChild(i, $event)"
>
</thing>
</div>
</template>
<script>
export default {
props: ['node'],
data() {
return {
myName: this.node.name,
myChildren: this.node.children.slice(0),
};
},
methods: {
updateParent() {
this.$emit('input', {name: this.myName, children: this.myChildren});
},
setchild(i, newChild) {
this.$set(this.myChildren, i, newChild);
}
}
}
</script>
这意味着树的每个节点:
这似乎可行,并且似乎避免了道具的变异。此处未显示但我发现很关键的一件事是为每个孩子设置唯一的ID。我是通过从全局计数器(在$root
上)顺序创建ID来实现的。