在VueJS中更新递归树视图的inital数组



我用vuejs中的递归组件为自己的树视图编写了本教程。所以输入数组看起来像这样:

let tree = {
label: 'root',
nodes: [
{
label: 'item1',
nodes: [
{
label: 'item1.1'
},
{
label: 'item1.2',
nodes: [
{
label: 'item1.2.1'
}
]
}
]
}, 
{
label: 'item2'  
}
]
}
<template>
<div>
...
<tree-menu 
v-for="node in nodes" 
:nodes="node.nodes" 
:label="node.label" />
...
</div>
<template
<script>
export default { 
props: [ 'label', 'nodes' ],
name: 'tree-menu'
}
</script>

所以基本上,一个标签和一个子数组的节点被传递给一个子节点。现在我想更新或删除一个节点(例如item1.1(,但在最外面的数组(此处为tree(中反映此更改,因为我想将此更新的结构发送到服务器。我怎样才能做到这一点?如果我更改节点的标签,它将在DOM中呈现,但tree数组不会更新。

以下是如何使用.sync修饰符递归更新:

Vue.config.devtools = false;
Vue.config.productionTip = false;
Vue.component('tree-node', {
template: `
<div style="margin-left: 5px;">
<input :value="label"
type="text"
@input="$emit('update:label', $event.target.value)" />
<tree-node v-for="(node, key) in nodes"
:key="key"
v-bind.sync="node" />
</div>
`,
props: ['label', 'nodes']
});
let tree = {
label: 'root',
nodes: [{
label: 'item 1',
nodes: [
{ label: 'item 1.1' },
{ label: 'item 1.2', 
nodes: [
{ label: 'item 1.2.1' }
]
}
]
},
{ label: 'item 2' }
]
};
new Vue({
el: '#app',
data: () => ({
tree
})
})
#app {
display: flex;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<div id="app">
<div>
<tree-node v-bind.sync="tree" />
</div>
<pre v-html="tree" />
</div>

v-bind.sync="node":label.sync="node.label" :nodes.sync="node.nodes"的简写。v-bind将所有对象成员作为标记的属性展开,从而为组件生成道具。

解决方案的另一半是用:value替换输入上的v-model+对@input$emit('update:propName', $event.target.value)调用,以更新父级中的.sync-ed属性。为了将其概念化,它是Vue公开的一个DIYv-model,因此可以对其进行自定义(您可以决定何时调用更新以及使用什么进行更新(。您可以将<input>替换为任何其他类型的输入,这取决于您正在绑定/修改的内容(复选框、文本区域、选择或框架可能具有的任何更高级的输入包装(。根据您想要自定义侦听器的输入类型:@change@someCustomEvent等…

.sync使所有事物在每个单独的层次上都具有反应性。由于所有内容都是:key-ed,因此实际上不会发生重新渲染(Vue只重新渲染实际更改的DOM元素(。如果不是这样的话,输入将在重新渲染时失去焦点。

更新的原则是:不在子级进行更改,而是更新父属性,后者通过v-bind将其发送回子级。

这与Vuex使用的原理完全相同。您称之为存储突变,它通过getter返回并修改本地值,而不是更改某些本地属性,但这种情况发生在使用该存储数据的任何组件上,而不仅仅是当前组件。

最新更新