Vuejs2 - 递归迭代“tr”元素

Vuejs2 - Iterate “tr” element recursively

我是 Vue 的新手,到目前为止我很喜欢它。但是,我遇到了以下问题,对于如何解决该问题的任何建议,我将不胜感激。

我想递归迭代对象以获得嵌套的 table。

我有这个模板:

<script type="text/x-template">
    <tr>
        <td><a v-on:click="toggle">[+]</a></td>
        <td>...</td>
    </tr>
    <tr is="row-item"  v-show="open" ...></tr>
</script>

它是递归的,所以每一行tr下面都有另一条隐藏线tr

当用户点击父行的[+]时,会出现子行。

我已经尝试将内容包装在 tbody 标签中,但后来我在 tbody 中得到了 tbody,这仍然是一个非法的 table 布局并中断它。

<script type="text/x-template">
    <tbody>
        <tr>
            <td>...</td>
            <td>...</td>
        </tr>
        <tr is="row-item" ...></tr>
    </tbody>
</script>

Fiddle: https://jsfiddle.net/rafi16d/puwcs9ay/

Vue@1.x 不需要一个根元素。没有我怎么办?

有没有人运行喜欢类似的东西?

谢谢。

(遗憾)Vue2 必须为每个组件提供一个真正的根元素。 所以我认为你没有那么多的可能性:

  • 做两个组件而不是一个组件,并用一个虚拟节点迭代它们:

    <table>
        <tbody>
            <template for="row in someRows">
                <tr>mainRow</tr>
                <tr>subRow</tr>
            </template>
        </tbody>
    </table>
    
  • 忘记想法做一个真正的table。使用 <div>related display css properties 来模拟布局。

好的,我做到了。红色边框是给你看结构的,你可能需要调整padding。

https://jsfiddle.net/guanzo/puwcs9ay/9/

我从 jQuery Datatables 如何嵌套行中借鉴的一些技巧和想法:

您几乎可以在 td 中放入任何内容。所以让根元素成为一个tr,嵌套一个td,colspan 100%,然后你可以嵌套一个table。因为你可以把 tr 放在 table 里面,所以递归开始了。

tr -> td -> table -> tr -> td -> table 无穷大

<td colspan="42">

42,或任何绝对高于您的列数的数字,基本上等同于 colspan="100%"

您也可以 - 并且可能应该 - 使用数组的长度来为 colspan 提供正确的列数,我只是懒惰。

内部 trs 已更改默认值 css。

.inner-tr{
    display: table;
    width:100%;
}

如果您在计算的 属性 中展平树(对其进行规范化),那么您可以渲染 HTML table 而无需在组件本身内递归,从而避免黑客攻击或生成无效 HTML.

Vue.component('tree-table-row', {
  data() {
    return {
      indent: 20,
      left_padding: 5
    };
  },
  props: ['node'],
  template: '#tree-table-row'
}); 
      
var app = new Vue({
  el: '#tree-as-table',
  data: {
    tree: {
      id: 0,
      value: "fruits",
      name: "root",
      children: [
      {
        id: 1,
        name: "A",
        children: [{
          id: 2,
          name: "B",
          value: "banana" 
        }],
        value: "apple"
      },
      {
        id: 3,
        name: "C",
        children: [{
          id: 4,
          name: "D",
          value: "durian" 
        }],
        value: "cherry"
      }
      ]
    }
  },
  computed: {
    tree_array() {
      return this.normalizedTree(this.tree, 0);
    }
  },
  methods: {
    normalizedTree(node, level) {
      var _this = this;
      var normal_element = {id: node.id, name: node.name, value: node.value, level: level};
      var array_fragment = [normal_element];
      if (node.children && node.children.length > 0) {
        var i;
        for (i=0; i < node.children.length; i++) {
          array_fragment = array_fragment.concat(_this.normalizedTree(node.children[i], level+1));
        };
      }
      return array_fragment;
    }
  }
});
.vue-table {
  border-collapse: collapse;
  font-family: sans-serif;
} 

td {
  border: 1px solid lightgrey;
  padding: 2px 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<script type="text/x-template" id="tree-table-row">
  <tr>
    <td :style="{'padding-left': node.level * indent + left_padding + 'px'}">{{node.name}}</td>
    <td>{{node.value}}</td>
  </tr>
</script>
    
<div id="tree-as-table">
  <table class="vue-table">
    <tr is="tree-table-row" v-for="(node, index) in tree_array" :node="node" :key="node.id"/>
  </table>
</div>