首页 > 解决方案 > 如何在自定义元素中制作自定义表格?

问题描述

我正在使用lit-element处理自定义元素。我想制作自己的自定义表格元素,但是有一些问题。

第一的。它似乎浏览器允许trtd标签只table

<!-- in html -->
<my-table>
  <tr>
    <td>A</td>
    <td>B</td>
  </tr>
</my-table>

<!-- chrome rendered -->
<my-table> A B </my-table>

第二。它可以用CSS模仿,但CSS不能实现colspan。

<my-table> <!-- display: table -->
  <my-tr> <!-- display: table-row -->
    <my-td>A</my-td> <!-- display: table-cell -->
    <my-td colspan="3">B</my-td> <!-- There is no way to implement colspan -->
  </my-tr>
</my-table>

第三。我尝试在主机上使用“显示:内容”进行样式设置。这似乎是工作,但主机没有像clientHeight.

class MyTd extends LitElement {
  render() {
    return html`
      <style>
        :host { display: content; }
        td {
          all: inherit; /* It make to inherit host's style */
          display: table-cell;
        }
      </style>
      <td>
        ${html`<slot></slot>`} // I don't know why it work.
      </td>
    `;
  }
}

// other js file.
const td = document.querySelector('my-td');
td.clientHeight; // 0

我可以覆盖clientHeight和其他东西(offsetHeightgetBoundingClientRect...),但我不知道这是正确的,这是唯一的方法。

有没有其他方法可以创建自定义表,或者我的想法有问题?

标签: htmlcsspolymercustom-elementlit-element

解决方案


对于自定义元素来说,这并不是一个很好的用例——问题是我为什么要<my-td><td>存在时使用并且在任何地方都可以使用?

可以在 CSS 中使用column-count来模拟表格,但您有更严重的问题 - 浏览器(和相关的 a11y 工具)将 DOM<table>视为结构化的数据表格,而您<my-table>的只是另一个自定义元素。

这也破坏了表格的 DOM 层次结构——即使您的元素包装了相关的表格元素,它们也不会继承扩展它们。

因此,对于您的第一个示例,您的 DOM 是这样的:

<my-table>
  #shadow-root
    <tr>
      <td>A</td>
      <td>B</td>
    </tr>
</my-table>

浏览器通常不会将单元格连接到行和将行连接到表格的任何操作都不会跨越这些影子 DOM 边界,并且它<tr>的呈现方式就像它位于新文档片段的根部一样。

同样,第三次尝试的 DOM 看起来像这样:

<my-table>
  #shadow-root
    <table>
       <my-tr>
         #shadow-root
           <tr>
             <my-td>
               #shadow-root
                 <td>

每一个影子根都是一个新的孤立片段。

问题变成了你想用这个结构做什么?

您是否想要一些看起来像表格但对行和单元格使用自定义元素的东西,请考虑使用display: grid布局。它比表格更强大,并且在自定义元素中,CSS 比相当不一致的display: table-cell.

如果您想要将某些东西结构化为表格,请考虑将整个表格放在影子根中并将数据作为属性传递

@customElement('my-table')
class MyTable 
  extends LitElement {
  render() {
    return html`
<table>
  ${this.items.map(i => html`
  <tr>
    <td>A</td>
    <td>B</td>
  </tr>`)}
</table>
    `;
  }

  @property({attribute: false})
  items: readonly RowRecordType[];
}

然后使用属性前缀调用它:

<my-table .items=${theListOfRows}></my-table>

最后,如果您想扩展 <td>,您可以使用is=语法添加它,但这在规范上有点死胡同,在 Safari 或 Opera 上根本不支持,并且在其余部分是不稳定的。

您可以扩展一个单元格:

class MyCell
    extends HTMLTableCellElement { ...

customElements.define('my-cell', MyCell, { extends: 'td' });

然后做:

<table>
  <tr>
    <td is="my-cell">A</td>
    <td is="my-cell">B</td>
  </tr>
</table>

但是,这不受 LitElement 支持,您最好直接实现自定义 Web 组件。


推荐阅读