Теневой DOM¶
Компоненты Lit используют shadow DOM для инкапсуляции своего DOM. Теневой DOM предоставляет возможность добавить к элементу отдельное изолированное и инкапсулированное дерево DOM. Инкапсуляция DOM — это ключ к обеспечению совместимости с любым другим кодом, включая другие веб-компоненты или компоненты Lit, функционирующие на странице.
Shadow DOM обеспечивает три преимущества:
- DOM scoping. API DOM, такие как
document.querySelector
, не найдут элементов в теневой DOM компонента, поэтому глобальным скриптам сложнее случайно сломать ваш компонент. - Разграничение стилей. Вы можете писать инкапсулированные стили для теневого DOM, которые не не влияют на остальную часть дерева DOM.
- Композиция. Теневой корень компонента, который содержит его внутренний DOM, отделен от дочерних элементов компонента. Вы можете выбрать, как дочерние элементы будут отображаться во внутреннем DOM компонента.
Дополнительная информация о теневом DOM:
- Shadow DOM v1: Self-Contained Web Components на сайте Web Fundamentals.
- Использование теневого DOM на MDN.
Старые браузеры
В старых браузерах, где нативный теневой DOM недоступен, можно использовать полифиллы веб-компонентов. Обратите внимание, что модуль polyfill-support
от Lit должен быть загружен вместе с полифиллами веб-компонентов. Подробности см. в Требования для устаревших браузеров.
Доступ к узлам в теневом DOM¶
Lit рендерит компоненты в свой renderRoot
, который по умолчанию является теневым корнем. Чтобы найти внутренние элементы, вы можете использовать API запросов DOM, например this.renderRoot.querySelector()
.
Корень renderRoot
всегда должен быть либо теневым корнем, либо элементом, для которого используются такие API, как .querySelectorAll()
и .children
.
Вы можете запросить внутренний DOM после первоначального рендеринга компонента (например, в firstUpdated
), или использовать геттерный шаблон:
1 2 3 4 5 6 7 |
|
LitElement предоставляет набор декораторов, которые обеспечивают сокращенный способ определения геттеров, подобных этому.
@query
, @queryAll
и @queryAsync
декораторы¶
Декораторы @query
, @queryAll
и @queryAsync
предоставляют удобный способ доступа к узлам во внутреннем DOM компонента.
Использование декораторов
Декораторы — это предложенная функция JavaScript, поэтому для использования декораторов вам потребуется компилятор типа Babel или TypeScript. Подробности см. в Использование декораторов.
@query
¶
Изменяет свойство класса, превращая его в геттер, который возвращает узел из корня рендеринга. Необязательный второй аргумент при значении true
выполняет запрос DOM только один раз и кэширует результат. Это может быть использовано в качестве оптимизации производительности в случаях, когда запрашиваемый узел не будет меняться.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Этот декоратор эквивалентен:
1 2 3 |
|
@queryAll
¶
Идентичен query
, за исключением того, что возвращает все совпадающие узлы, а не один узел. Это эквивалентно вызову querySelectorAll
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Здесь _divs
вернет оба элемента <div>
в шаблоне. Для TypeScript типизация свойства @queryAll
— это NodeListOf<HTMLElement>
. Если вы точно знаете, какой тип узлов вы хотите получить, тип может быть более конкретным:
1 2 |
|
Восклицательный знак (!
) после buttons
— это оператор TypeScript non-null assertion operator. Он указывает компилятору, что кнопки
всегда должны быть определены, и никогда не должны быть null
или undefined
.
@queryAsync
¶
Аналогичен @query
, только вместо непосредственного возврата узла возвращает Promise
, который разрешается в этот узел после завершения рендеринга любого ожидающего элемента. Код может использовать это вместо ожидания обещания updateComplete
.
Это полезно, например, если узел, возвращаемый @queryAsync
, может измениться в результате изменения другого свойства.
Рендеринг дочерних узлов со слотами¶
Ваш компонент может принимать дочерние элементы (например, элемент <ul>
может иметь дочерние элементы <li>
).
1 2 3 |
|
По умолчанию, если элемент имеет теневое дерево, его дочерние узлы не отображаются вообще.
Чтобы отобразить дочерние элементы, ваш шаблон должен включать один или несколько <slot>
элементов, которые выступают в качестве держателей для дочерних узлов.
Использование элемента slot
¶
Чтобы отобразить дочерние элементы, создайте для них элемент <slot>
в шаблоне элемента. Дочерние элементы не перемещаются в дереве DOM, но они отображаются так, как если бы они были дочерними элементами <slot>
. Например:
Использование именованных слотов¶
Чтобы назначить ребенка на определенный слот, убедитесь, что атрибут slot
ребенка совпадает с атрибутом name
слота:
-
Именованные слоты принимают детей только с совпадающим атрибутом
slot
Например,
<slot name="one"></slot>
принимает детей только с атрибутомslot="one"
. -
Дети с атрибутом
slot
будут отображаться только в слоте с соответствующим атрибутомname
Например,
<p slot="one">...</p>
будет помещен только в<slot name="one"></slot>
.
Указание содержимого обратного хода слота¶
Вы можете указать содержимое отката для слота. Запасной контент отображается, когда слоту не назначен ребенок.
1 |
|
Рендеринг резервного содержимого
Если слоту назначены дочерние узлы, его содержимое не отображается. Слот по умолчанию без имени принимает любые дочерние узлы. Он не будет отображать резервное содержимое, даже если единственными назначенными узлами являются текстовые узлы, содержащие пробелы, например <example-element> </example-element>
. При использовании выражения Lit в качестве дочернего элемента пользовательского элемента убедитесь, что в соответствующих случаях используется нерендерируемое значение, чтобы все содержимое слота с возвратом было отрисовано. Дополнительные сведения см. в разделе удаление дочернего содержимого.
Доступ к дочерним элементам слотов¶
Чтобы получить доступ к дочерним элементам, назначенным слотам в корне тени, вы можете использовать стандартные методы slot.assignedNodes
или slot.assignedElements
с событием slotchange
.
Например, вы можете создать геттер для доступа к назначенным элементам для определенного слота:
1 2 3 4 |
|
Вы также можете использовать событие slotchange
для выполнения действий при изменении назначенных узлов. В следующем примере извлекается текстовое содержимое всех дочерних узлов со слотами.
1 2 3 4 5 6 7 8 9 10 11 |
|
Для получения дополнительной информации смотрите HTMLSlotElement на MDN.
@queryAssignedElements
и @queryAssignedNodes
декораторы¶
@queryAssignedElements
и @queryAssignedNodes
преобразуют свойство класса в геттер, возвращающий результат вызова slot.assignedElements
или slot.assignedNodes
соответственно для заданного слота в теневом дереве компонента. Используйте их для запроса элементов или узлов, назначенных данному слоту.
Обе принимают необязательный объект со следующими свойствами:
Свойство | Описание |
---|---|
flatten | Булево значение, указывающее, нужно ли сплющивать назначенные узлы, заменяя все дочерние <slot> элементы их назначенными узлами. |
slot | Имя слота, определяющее слот для запроса. Оставьте неопределенным, чтобы выбрать слот по умолчанию. |
selector (только для queryAssignedElements ) | Если указано, возвращаются только те назначенные элементы, которые соответствуют данному CSS-селектору. |
Решение о том, какой декоратор использовать, зависит от того, хотите ли вы запрашивать текстовые узлы, назначенные слоту, или только узлы элементов. Это решение зависит от конкретного случая использования.
Использование декораторов
Декораторы — это предложенная функция JavaScript, поэтому для использования декораторов вам потребуется компилятор типа Babel или TypeScript. Подробности см. в Использование декораторов.
1 2 3 4 5 |
|
Приведенные выше примеры эквивалентны следующему коду:
1 2 3 4 5 6 7 8 9 |
|
Настройка корня рендеринга¶
У каждого компонента Lit есть корень рендера — узел DOM, который служит контейнером для его внутреннего DOM.
По умолчанию LitElement создает открытый shadowRoot
и осуществляет рендеринг внутри него, создавая следующую структуру DOM:
1 2 3 4 5 |
|
Есть два способа настроить корень рендеринга, используемый LitElement:
- Установка
shadowRootOptions
. - Реализация метода
createRenderRoot
.
Установка shadowRootOptions
.¶
Самый простой способ настроить корень рендера — установить статическое свойство shadowRootOptions
. Реализация createRenderRoot
по умолчанию передает shadowRootOptions
в качестве аргумента опций в attachShadow
при создании корня тени компонента. Он может быть установлен для настройки любых опций, разрешенных в словаре ShadowRootInit, например, mode
и delegatesFocus
.
1 2 3 4 5 6 |
|
Дополнительные сведения см. в Element.attachShadow() на MDN.
Реализация createRenderRoot
¶
Реализация по умолчанию createRenderRoot
создает открытый корень тени и добавляет к нему любые стили, заданные в поле класса static styles
. Подробнее о стилях см. в Styles.
Чтобы настроить корень рендеринга компонента, реализуйте createRenderRoot
и верните узел, в который должен рендериться шаблон.
Например, для рендеринга шаблона в основном дереве DOM в качестве дочерних элементов, реализуйте createRenderRoot
и верните this
.
Рендеринг в дочерние элементы
Рендеринг в дочерние элементы, а не в теневой DOM, как правило, не рекомендуется. Ваш элемент не будет иметь доступа к DOM или к диапазону стилей, и он не сможет компоновать элементы в своем внутреннем DOM.