【问题标题】:How to make a Vue.js component of some (but not all) table cells in a table row?如何在表格行中制作一些(但不是全部)表格单元格的 Vue.js 组件?
【发布时间】:2018-10-29 22:15:03
【问题描述】:

我有一些相关的和相邻的表列,我想将它们分组到同一个组件中。但是 Vue.js 模板系统有这个限制,只有一个标签可以直接在<template> 中。通常这个无意义的包装是<div>。但是我可以在表格中使用什么?

我可以为此滥用<span> 之类的标签,但后果是不可接受的。同一列中的单元格大小不同,表格边框不折叠。有没有办法让包装标签在理想情况下根本不会出现在 HTML 中,或者至少像 <div> 一样中性?

表格行:

<template>
    <tr v-for="thing in things">
        <td>{{thing.name}}</td>
        <size-component :size="thing.size"></size-component>
        <time-component :time="thing.time"></time-component>
    </tr>
</template>

列大小:

<template>
    <wrap>
        <td>{{size.x}}</td>
        <td>{{size.y}}</td>
        <td>{{size.z}}</td>
    </wrap>
</template>

时间列:

<template>
    <wrap>
        <td>{{time.h}}</td>
        <td>{{time.m}}</td>
        <td>{{time.s}}</td>
    </wrap>
</template>

编辑:

对我来说,这归结为问题,在&lt;tr&gt; 中没有标签可以将&lt;td&gt;s 分组(就像&lt;tr&gt;s 可以用多个&lt;tbody&gt; 标签分组在&lt;table&gt; 中)。比较Is there a tag for grouping "td" or "th" tags? 语义上&lt;colgroup&gt; 是为此目的而设计的,但这并没有帮助。

对我来说,使用 vue-fragment 原来是正确的解决方案:

<template>
    <fragment>
        <td>{{size.x}}</td>
        <td>{{size.y}}</td>
        <td>{{size.z}}</td>
        <td>{{volume}}</td>
    </fragment>
</template>

<script>
    import { Fragment } from 'vue-fragment';

    export default {
        computed: {
            volume() { return this.size.x * this.size.y * this.size.z },
        },
        components: { Fragment },
        props: ['size']
    }
</script>

【问题讨论】:

    标签: html templates vue.js html-table


    【解决方案1】:

    你说得对,这是 Vue 的限制,与 the diffing algorithm 有关。但是,您可以使用函数式组件来呈现多个根元素。

    <script>
    export default {
      functional: true,
      props: {
        size: {
          type: Object,
          default: () => ({
            x: 1,
            y: 2,
            z: 3
          })
        }
      },
      render: (createElement, context) => [
        createElement('td', context.props.size.x),
        createElement('td', context.props.size.y),
        createElement('td', context.props.size.z)
      ]
    }
    </script>
    

    另一种选择是使用插件vue-fragments

    【讨论】:

    • 哇,多么混乱的话题。你知道我如何在createElement 中使用计算属性吗?假设有volume() { return size.x * size.y * size.z }。直观的解决方案是context.computed.volume,但这不起作用。
    • 好的,功能组件是无状态的,所以如果我理解正确的话,它们不应该有volume()之类的东西。我的印象是,如果不将复杂性增加到我不想处理的程度,我就无法完成我想要的事情。重点是通过使用几个小组件而不是一个大组件来降低复杂性。
    • 昨天我没有让 vue-fragment 工作,但事实证明这是最简单的解决方案。谢谢。
    • vue-fragment 是我的偏好,有点像portal-vue,但语法更简单。
    【解决方案2】:

    要将计算添加到@Andreas 解决方案,可以引用父属性。

    演示CodeSandbox

    功能组件

    export default {
      functional: true,
      props: {
        size: {
          type: Object,
          default: () => ({
            x: 1,
            y: 2,
            z: 3
          })
        }
      },
      render: (createElement, context) => [
        createElement("td", context.props.size.x),
        createElement("td", context.props.size.y),
        createElement("td", context.props.size.z),
        createElement("td", context.parent.volume(context.props.size))
      ]
    };
    

    父组件

    export default {
      components: {
        SizeComponent
      },
      data() {
        return {
          things: [
            {
              name: 'aName',
              size: { x: 1, y: 2, z: 3 }
            }
          ]
        };
      },
      mounted() {
        // test it is reactive
        setTimeout(()=> { this.things[0].size.x = 2 }, 3000) 
      },
      computed: {
        volume() {
          return (size) => size.x * size.y * size.z;
        }
      },
    }
    

    【讨论】:

    • 感谢您完成回答。我相信这会对某人有所帮助。无论如何,我觉得这太复杂了。我想我会改为从&lt;table&gt; 切换到display: table。所以简单的解决方案应该是旧的&lt;div&gt;
    • 我希望你能用你喜欢的解决方案发布答案​​。
    • &lt;table&gt; 切换到display: table 不起作用,顺便说一句。同样的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    • 2016-10-08
    • 2020-06-03
    • 2016-12-10
    • 1970-01-01
    • 1970-01-01
    • 2012-02-15
    相关资源
    最近更新 更多