Vue js。递归成分毁了我的生命

时间:2017-09-25 10:41:33

标签: javascript recursion vue.js vuejs2

我想从XML文件创建树视图,我这样做了。但是,当我决定让它更灵活时,我遇到了一些问题。

以下是我的组件:

Vue.component('elname', {
  props: ['text'],
  template: '<span>{{ text }}</span>'
})


Vue.component('recursive', {
  props: ['d', 'liname', 'openclose'],
  template: '#recursive',
  data: function() {
    return {
      seen: true
    }
  }
  }
)

,Vue对象如下所示:

var appp = new Vue({
  el: '#here',
  data: function(){
    return {
      friends: '',
    }
  },
  beforeMount() {
    parser = new DOMParser();
    var response = "<scope><friend><name>Alex</name><hobbies><h>music</h><h>salsa</h></hobbies></friend><friend><name>Natasha</name><hobbies><h>hiking</h></hobbies></friend></scope>";
    xml = parser.parseFromString(response, 'text/xml');
    children = xml.getElementsByTagName('scope')[0];
    this.friends = children;
  }
})

我在seen组件

中有这个变量recursive
Vue.component('recursive', {
  props: ['d', 'liname', 'openclose'],
  template: '#recursive',
  data: function() {
    return {
      seen: true // <-- here it is
    }
  }
  }
)

它必须更改其值@click事件以隐藏嵌套列表(请参阅JSfiddle),但是当它更改时,它会更新其值为SEVERAL组件。

如何仅在特定组件中更新其值?

这是一个模板:

<div id="here">
  <recursive :d="friends" openclose="[-]"></recursive>
</div>

<template id="recursive">
  <div>
    <ul v-if="d.children.length != 0">
      <li v-for="n in d.childNodes" @click="seen = !seen">
        <elname :text="n.tagName"></elname>
        {{ openclose }}
        {{seen}} <!-- it is just for testing purposes to illustrate how seen var changes -->
        <recursive :d="n" openclose="[-]"></recursive>
      </li>
    </ul>
    <ul v-else>
      <elname :text="d.textContent"></elname>
    </ul>
  </div>
</template>

3 个答案:

答案 0 :(得分:1)

您有两个问题:

  1. 您需要使用click.stop,以便点击事件不会传播到父母
  2. 您需要recursive内的组件来处理切换
  3. Vue.component('elname', {
      props: ['text'],
      template: '<span>{{ text }}</span>'
    });
    
    Vue.component('recursive', {
      props: ['d', 'openclose'],
      template: '#recursive',
      components: {
        toggler: {
          data() {
              return {
                seen: true
              }
            },
            methods: {
              toggle() {
                this.seen = !this.seen;
              }
            }
        }
      }
    });
    
    var appp = new Vue({
      el: '#here',
      data: function() {
        return {
          friends: '',
        }
      },
      beforeMount() {
        parser = new DOMParser();
        var response = "<scope><friend><name>Alex</name><hobbies><h>music</h><h>salsa</h></hobbies></friend><friend><name>Natasha</name><hobbies><h>hiking</h></hobbies></friend></scope>";
        xml = parser.parseFromString(response, 'text/xml');
        children = xml.getElementsByTagName('scope')[0];
        this.friends = children;
      }
    })
    <script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.min.js" integrity="sha256-Ab5a6BPGk8Sg3mpdlsHzH6khPkniIWsvEuz8Fv/s9X8=" crossorigin="anonymous"></script>
    
    <div id="here">
      <recursive :d="friends" openclose="[-]"></recursive>
    </div>
    
    <template id="recursive">
      <div>
        <ul v-if="d.children.length != 0">
          <li is="toggler" v-for="n in d.childNodes" inline-template>
            <div @click.stop="toggle">
              <elname :text="n.tagName"></elname>
              {{ openclose }}
              <recursive v-if="seen" :d="n" openclose="[-]"></recursive>
            </div>
          </li>
        </ul>
        <ul v-else>
          <elname :text="d.textContent"></elname>
        </ul>
      </div>
    </template>

答案 1 :(得分:0)

目前,元素上有1个seen变量,它控制所有子元素的状态。因此,点击任何孩子都会更改父级中的seen值并显示/隐藏此父级的所有子级。

解决方案1 ​​

seen变量的类型更改为数组 - 与children数组的长度相同。并将处理程序更改为@click="seen[i] = !seen[i]"

解决方案2

将单击侦听器移动到子项。因此,将@click="seen = !seen"放在模板中最外层的div上,并仅在v-if="d.children.length && seen"

上呈现整个列表

Vue.component( 'recursive-list', {
  props: ["d"],
  data: () => ({ expand: true }),
  template: `<div style="margin: 5px">
    <div v-if="Array.isArray(d)"
      style="border: 1px solid black">
      <button @click="expand = !expand">Show/Hide</button>
      <template v-show="expand">
        <recursive-list v-for="e in d" :d="e" />
      </template>
      <p v-show="!expand">...</p>
    </div>
    <p v-else>{{d}}</p>
  </div>`
} )

new Vue({
  el: '#main',
  data: { d: ["Text", ["a","b","c"],[[1,2,3],[4,5,6],[7,8]]]
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.js"></script>

<div id='main'>
  <h3>List:</h3>
  <recursive-list :d="d"></recursive-list>
</div>

答案 2 :(得分:0)

我对你的结构进行了一些修改,也许这不是你需要的,但我认为会更清楚。

<template id="tree">
  <div>
    <ul v-for="(tree, k, idx) in tree.childNodes">
      <node :tree="tree" :idx="idx"></node>
    </ul>
  </div>
</template>

<template id="node">
  <li>
    <div v-if="tree.childNodes.length">
      <span @click="seen = !seen">{{ tree.tagName }}</span>
      <span>{{ seen }}</span>
      <ul v-for="(node, k, id) in tree.childNodes">
        <node :tree="node" :idx="id"></node>
      </ul>
    </div>
    <div v-else>{{ tree.textContent }}</div>
  </li>
</template>

https://jsfiddle.net/jonataswalker/Lw52t2dv/