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

Я работаю над пользовательским элементом с помощью 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...), но я не знаю, правильно ли это и это единственный способ.

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


person hyeong-min    schedule 31.10.2018    source источник
comment
Вы можете использовать количество столбцов css: 3; как альтернатива colspan.   -  person ElusiveCoder    schedule 31.10.2018
comment
Вы должны взглянуть на этот вопрос: stackoverflow.com/q/41585527/4600982   -  person Supersharp    schedule 31.10.2018


Ответы (1)


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

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

person Keith    schedule 05.05.2021