更新 VueJS 中递归树视图的初始数组

Update the inital array of a recursive treeview in VueJS

我正在学习 this 我自己的树视图教程,其中包含 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>

对于 :label.sync="node.label" :nodes.sync="node.nodes"

v-bind.sync="node" 是 shorthand。 v-bind 将所有对象成员解包为标签的属性,从而为组件生成 props。

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

.sync 使每个级别的一切都具有反应性。因为一切都是 :key-ed,实际上没有重新渲染发生(Vue 只重新渲染实际改变的 DOM 元素)。如果不是这种情况,输入将在重新渲染时失去焦点。

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

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