: контекст хоста не работает должным образом в веб-компоненте Lit-Element - PullRequest
0 голосов
/ 01 мая 2020

У меня есть два веб-компонента на Lit-элементах - один units-list, который содержит множество units-list-item элементов. Элементы units-list-item имеют два разных режима отображения: компактный и подробный. Поскольку элемент списка поддерживает бесконечную прокрутку (и, следовательно, может содержать несколько тысяч единиц), нам нужен любой механизм, который переключается между двумя режимами, чтобы быть как можно более быстрым.

Именно поэтому я подумал, что идеальным решением было бы используйте псевдоселектор :host-context() в стилях для элемента units-list-item, так как каждый элемент units-list-item может переключаться между двумя режимами отображения, просто изменяя класс, примененный к предку (который будет в теневом DOM элемента units-list).

Для уточнения приведена соответствующая разметка элемента units-list. Обратите внимание, что классы «триггеров» применяются к элементу #list-contents, который является частью шаблона units-list.

<div id="list-contents" class="${showDetails ? 'detail-view table' : 'compact-view table'}">
    ${units.map(unit => html`<units-list-item .unit="${unit}"></units-list-item>`)}
</div>

Как видите, флаг showDetails определяет, применяется ли класс "detail-view" или "compact-view" к div, содержащему все элементы units-list-item. Эти классы определенно применяются правильно.

Вот полный метод рендеринга из элемента units-list-item (ненужная разметка удалена):

render() {
    const {unit} = this;
    // the style token below injects the processed stylesheet contents into the template
    return html`
        ${style}
        <div class="row compact">
            <!-- compact row markup here -->
        </div>
        <div class="row detail">
            <!-- detail row markup here -->
        </div>
    `;
}

Затем у меня в units-list-item есть следующее стили элемента (мы используем S CSS, поэтому однострочные комментарии не являются проблемой):

    // This SHOULD hide the compact version of the row when the 
    // unit list has a "detail" class applied
    :host-context(.detail-view) div.row.compact {
        display: none !important;
    }

    // This SHOULD hide the detail version of the row when the
    // unit list has a "compact" class applied
    :host-context(.compact-view) div.row.detail {
        display: none !important;
    }

В моем понимании: host-context selector говорит, что это должно работать, но Chrome просто отображает обе версии строки каждый раз, а инструменты Chrome dev показывают, что селекторы никогда не совпадают ни с одной из строк.

Я знаю, что есть несколько альтернатив, которые будут работать, но это единственный, о котором я знаю, позволил бы всему списку модулей переключать режимы, изменяя один класс на родительском элементе. Любое другое решение, которое я рассмотрел, потребовало бы, по крайней мере, обновления атрибута класса для каждого элемента units-list-item в списке. Я хотел бы избежать этого, если это возможно.

Конечно, моя главная задача - просто сделать эту работу, если это возможно, но мне также любопытно несколько вещей и я не могу найти какую-либо информацию о них. Два вопроса, на которые я не могу найти ответ:

  1. Когда :host-context используется внутри элемента, который сам является частью теневого DOM, учитывает ли он теневой DOM родительского элемента для быть "контекстом хоста", или он прыгает "полностью" в DOM документа?
  2. Если это первый, :host-context будет переходить несколько теневых границ DOM? Скажем, у меня есть пользовательский элемент page, который содержит пользовательский элемент list, который сам содержит много пользовательских элементов item. Если этот элемент item имеет правило :host-context, будет ли браузер сначала сканировать теневой DOM элемента list, а затем, если ничего не соответствует, сканировать теневой DOM элемента page и, если все еще ничего не найдено, затем отсканируйте основной документ DOM до тега <html>?

Ответы [ 2 ]

1 голос
/ 01 мая 2020

Пример использования css porperties, как говорит Дэнни Энгельман, для достижения вашей цели

  customElements.define('list-item', class extends HTMLElement {
    constructor() {
      const style = document.createElement('style');
      const divcompact = document.createElement('div');
      divcompact.innerHTML = "compact";
      divcompact.className = "compact";
      const divdetail = document.createElement('div');
      divdetail.innerHTML = "detail";
      divdetail.className = "detail";
      let shadow = super().attachShadow({
        mode: 'open'
      });
      shadow.append(style, divcompact, divdetail);
      style.innerHTML = `
      .compact {
          background-color: red;
          display: var(--display-compact, block);
      }
      .detail {
	        background-color: green;
          display: var(--display-detail, block);
      }
      `
    }
  });
.compact-view {
  --display-detail: none;
}
.detail-view {
  --display-compact: none;
}

.box {
  width: 200px;
  height: 50px;
  border: solid 1px black;
  margin: 5px;  
}
    <div class="box">
    no class applied
        <list-item>test</list-item>
    </div>
    <div class="compact-view box">
    compact view
        <list-item>test</list-item>
    </div>
    <div class="detail-view box">
    detail view
        <list-item>test</list-item>
    </div>
1 голос
/ 01 мая 2020

Нет поддержки :host-context в FireFox или Safari

Последнее обновление за месяц go - и Mozilla, и Apple не собираются реализовать это.

Похоже, что он будет удален из объекта c: https://github.com/w3c/csswg-drafts/issues/1914

Одной из альтернатив является использование CSS свойств (которые стекаются в shadowDOM)

JSFiddle: https://jsfiddle.net/CustomElementsExamples/jb6c81ou/

  • с использованием host-context для Chrome и Edge
  • с использованием CSS свойства для других браузеров
...