Vuejs2 - 递归迭代“tr”元素

时间:2017-05-31 13:27:55

标签: recursion vue.js vuejs2 vue-component

我对Vue很新,我到目前为止都喜欢它。但是,我遇到了以下问题,如果有任何建议,我会感激不尽。

我想在对象上递归迭代以获得嵌套表。

我有这个模板:

<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,这仍然是非法的表格布局并打破它。

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

小提琴:https://jsfiddle.net/rafi16d/puwcs9ay/

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

有没有人碰到类似的东西?

感谢。

3 个答案:

答案 0 :(得分:1)

(可悲)Vue2迫切需要每个组件的真正根元素。 因此,我认为你没有那么多的可能性:

  • 做两个组件而不是一个组件,并且它们都是虚拟节点:

    <table>
        <tbody>
            <template for="row in someRows">
                <tr>mainRow</tr>
                <tr>subRow</tr>
            </template>
        </tbody>
    </table>
    
  • 忘掉做真正的桌子的想法。使用<div>related display css properties代替模拟布局。

答案 1 :(得分:1)

好吧,我设法做到了。红色边框是供您查看结构的,您可能需要调整填充。

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

我从jQuery Datatables如何嵌套行中借用了几个hacks和想法:

您可以在td中添加任何内容。因此,将根元素设为tr,使用colspan 100%嵌套td,然后可以嵌套表。由于您可以将tr放在table内,因此递归开始。

tr - &gt; td - &gt; table - &gt; tr - &gt; td - &gt;无限期table

<td colspan="42">

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

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

内部trs更改了默认的css。

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

答案 2 :(得分:0)

如果在计算的属性中展平树(对其进行规范化),则可以呈现HTML表而无需在组件本身内部进行递归,从而避免黑客入侵或生成无效的HTML。

    public static string Capture(IWebDriver driver, string screenShotName)
    {
        ITakesScreenshot ts = (ITakesScreenshot)driver;
        Screenshot screenshot = ts.GetScreenshot();
        string pth = System.Reflection.Assembly.GetCallingAssembly().CodeBase;
        string finalpth = pth.Substring(0, pth.LastIndexOf("bin")) + "ErrorScreenshots\\" + screenShotName + ".png";
        string localpath = new Uri(finalpth).LocalPath;
        screenshot.SaveAsFile(localpath, ScreenshotImageFormat.Png);
        return localpath;
    }
    public void GetResult()
    {            
        var status = NUnit.Framework.TestContext.CurrentContext.Result.Outcome.Status;
        var stackTrace = "<pre>" + NUnit.Framework.TestContext.CurrentContext.Result.StackTrace + "</pre>";
        var errorMessage = NUnit.Framework.TestContext.CurrentContext.Result.Message;

        if (status == TestStatus.Failed)
        {
            string screenShotPath = Capture(DriverContext.Driver, "ScreenShotName");
            Test.Log(LogStatus.Pass, stackTrace + errorMessage);
            Test.Log(LogStatus.Pass, "Snapshot below: " + Test.AddScreenCaptureFromPath(screenShotPath));
        }
        DriverContext.Driver.Quit();
    }
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;
}