如何在自定义元素中制作自定义表格?

hye*_*min 5 html css polymer custom-element lit-element

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

第一的。浏览器似乎只允许tr标签。tdtable

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

<!-- chrome rendered -->
<my-table> A B </my-table>
Run Code Online (Sandbox Code Playgroud)

第二。它可以模仿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>
Run Code Online (Sandbox Code Playgroud)

第三。我尝试在主机上使用“显示:内容”进行样式设置。这似乎有效,但主机没有像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
Run Code Online (Sandbox Code Playgroud)

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

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

Kei*_*ith 0

对于自定义元素来说,这并不是一个很好的用例 - 问题是为什么我要使用它存在并且可以<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>
Run Code Online (Sandbox Code Playgroud)

浏览器通常将单元格连接到行以及将行连接到表所做的任何操作都不会跨越这些影子 DOM 边界,并且<tr>渲染得完全就像它位于新文档片段的根部一样。

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

<my-table>
  #shadow-root
    <table>
       <my-tr>
         #shadow-root
           <tr>
             <my-td>
               #shadow-root
                 <td>
Run Code Online (Sandbox Code Playgroud)

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

问题是你想用这个结构做什么?

您想要看起来像表格但对行和单元格使用自定义元素的东西吗?请考虑使用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[];
}
Run Code Online (Sandbox Code Playgroud)

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

@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[];
}
Run Code Online (Sandbox Code Playgroud)

最后,如果你想扩展, <td>你可以添加到它is=,但这在规范上有点死胡同,在 Safari 或 Opera 上根本不支持,而且在其他方​​面也很不稳定。

您可以扩展单元格:

class MyCell
    extends HTMLTableCellElement { ...

customElements.define('my-cell', MyCell, { extends: 'td' });
Run Code Online (Sandbox Code Playgroud)

然后执行以下操作:

<my-table .items=${theListOfRows}></my-table>
Run Code Online (Sandbox Code Playgroud)

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