Как сделать пользовательскую таблицу в пользовательском элементе?

Я работаю над пользовательским элементом с lit-element. Я хочу сделать свой собственный элемент таблицы, но есть некоторые проблемы.

Первый. Казалось, браузер позволяет tr , td теги только для 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>

В третьих. Я пытаюсь стилизовать с "display: content" на хосте. Казалось бы, работа, но хост не имеет данных для размеров коробки, как 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 и что-нибудь еще (offsetHeight, getBoundingClientRect...) но я не знаю, что это правильно, и это единственный способ.

Есть ли другой способ создать пользовательскую таблицу или в моем мышлении что-то не так?

1 ответ

На самом деле это не лучший вариант использования настраиваемого элемента - вопрос в том, зачем мне использовать <my-td> когда есть и везде работает?

Вы можете использовать column-count в CSS для имитации таблиц, но у вас есть более серьезные проблемы - браузеры (и связанные с ними инструменты) видят 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, и вам лучше напрямую реализовать свой собственный веб-компонент.

Другие вопросы по тегам