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

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

Первый. Казалось, браузер поддерживает теги 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 ...), но я не знаю, что это правильно, и это единственный способ.

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

Вы можете использовать css column-count: 3; как альтернатива colspan.

ElusiveCoder 31.10.2018 14:04

Вам стоит взглянуть на этот вопрос: stackoverflow.com/q/41585527/4600982

Supersharp 31.10.2018 14:24
4
2
1 202
1

Ответы 1

На самом деле это не лучший вариант использования настраиваемого элемента - вопрос в том, зачем мне использовать <my-td>, если <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, и вам лучше напрямую реализовать свой собственный веб-компонент.

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