使用 VueJS 嵌套输入的树视图

Treeview with nested inputs with VueJS

我正在尝试构建一个包含输入的树视图组件以更改我的源 json。

绑定部分似乎工作正常,但分支上的 hide/show 操作已损坏:

HTML :

<div id="app">
  <tree :data="json" :link="json"></tree>

  <p>Outside component :</p>
  <pre>{{json}}</pre>
</div>

JS :

let json = {
  nodeA: {
    nodeA1 : "valueA1",
    nodeA2 : "valueA2"
  },
  nodeB: "valueB",
  nodeC: {
    nodeC1 : "valueC1",
    nodeC2 : "valueC2"
  }
};

Vue.component('tree', {
  name: 'treeview',
  props: [
    'data', 
    'link'
  ],
  template: `<ul>
        <li v-for="(val, key) in data">
            <input type="text" v-if="isLeaf(val)" v-model=link[key]>
            <span @click="toggle">{{key}}</span>
            <tree v-if="!isLeaf(val)" v-show="show" :data="val" :link="link[key]">
            </tree>
        </li>
    </ul>`,
  data: function() {
    return {
      show: false
    };
  },
  methods: {
    isLeaf: function(node) {
      return typeof node != 'object';
    },
    toggle: function() {
      this.show = !this.show;
    }
  }
});

new Vue({
  el: '#app',
  data: {
    json: json
  }
});

https://codepen.io/anon/pen/EZKBwL

如您所见,单击第一个分支 ("nodeA") 会同时激活第一个和第三个分支...

我认为问题出在父组件上发生的点击,但我找不到修复代码的方法。

这是因为您将所有元素绑定到同一个参数。

要单独切换每个元素的可见性,您需要将元素状态存储在它自己的位置,例如对象的字段或数组。

但我想更好的解决方案是通过单击在目标元素上切换 class 并通过 css 通过 class 控制可见性。

您的所有分支都 hiding/showing 在一起,因为您使用单个变量 show 来隐藏和显示这两个分支,您必须为每个节点使用不同的变量。

拥有与节点数量一样多的变量是不切实际的,但您可以拥有如下所示的散列:

  data: function() {
    return {
      show: {}
    };
  },

并更改切换方法,通过在该 show 散列中为该节点创建一个键来为每个节点设置变量。您可以为此使用 vm.$set,其中 在对象上设置 属性。如果对象是反应性的,确保 属性 创建为反应性 属性 并触发视图更新。

toggle: function(node) {
  if(this.show[node]){
    this.$set(this.show, node, false)
  } else {
    this.$set(this.show, node, true)
  }
} 

你也需要在HTML中做相应的修改,可以在working codepen中查看here

您可能需要每个节点的 show 字段来分别切换它们的可见性,在我的 improved example 中,我使用的是这样的数据结构:

{
    "nodeA": {
        "value": {
            "nodeA1": {
                "value": "valueA1",
                "show": false
            },
            "nodeA2": {
                "value": "valueA2",
                "show": false
            }
        },
        "show": true
    },
    "nodeB": {
        "value": "valueB",
        "show": true
    }
}

我的模板:

<ul>
    <li v-for="(val, key) in data" v-show='val.show'>
        <input type="text" v-if="isLeaf(val)" v-model='link[key].value'>
        <span @click="toggle(val.value)">{{key}}</span>
        <tree v-if="!isLeaf(val)" :data="val.value" :link="val.value">
        </tree>
    </li>
</ul>

方法:

{
    isLeaf: function(node) {
        return typeof node.value != 'object';
    },
    toggle: function(value) {
        for (const nodeName in value) {
            value[nodeName].show = !value[nodeName].show;
        }
    }
}