Spec-Zone.ru › Lit 2

Композиция компонентов

Самый распространённый способ справиться со сложностью и разделить код Lit на отдельные блоки — композиция компонентов, то есть процесс создания большого сложного компонента из небольших и простых компонентов. Представьте, что вам поручили реализовать экран пользовательского интерфейса:

Screenshot of an application that displays a set of animal photos. The application has a top bar with a title ("Fuzzy") and a menu button. A left menu drawer is open, showing a set of options.

Вы, вероятно, сможете определить области, реализация которых потребует определённых усилий. Скорее всего, они могут стать компонентами.

Изолируя сложную логику в отдельных компонентах, вы значительно упрощаете задачу, а затем можете объединить эти компоненты, чтобы создать общий дизайн.

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

В Lit композиция выполняется путём добавления элементов в шаблон — как встроенных HTML-элементов, так и пользовательских элементов.

render() {
  return html`
    <top-bar>
      <icon-button icon="menu" slot="nav-button"></icon-button>
      <span slot="title">Fuzzy</span>
    </top-bar>
    `;
}

Что делает компонент удачным

Решая, как разделить функциональность, учитывайте несколько признаков, которые помогут определить, когда стоит создать новый компонент. Фрагмент пользовательского интерфейса может стать хорошим кандидатом на роль компонента, если выполняется одно или несколько из следующих условий:

  • У него есть собственное состояние.
  • У него есть собственный шаблон.
  • Он используется более чем в одном месте — в этом компоненте или в нескольких компонентах.
  • Он хорошо выполняет одну задачу.
  • У него есть чётко определённый API.

Многоразовые элементы управления, такие как кнопки, флажки и поля ввода, могут стать отличными компонентами. Однако более сложные элементы интерфейса, например выдвижные панели и карусели, также хорошо подходят для создания компонентов.

Передача данных вверх и вниз по дереву

При обмене данными с вложенными компонентами обычно следует придерживаться модели DOM: свойства вниз, события вверх.

  • Свойства вниз. Обычно предпочтительнее задавать свойства вложенного компонента, чем вызывать его методы. В шаблонах Lit и других декларативных системах шаблонов свойства задавать просто.

  • События вверх. На веб-платформе отправка событий — стандартный способ передачи элементами информации вверх по дереву, часто в ответ на действия пользователя. Это позволяет компоненту-хозяину обработать событие или преобразовать его либо повторно отправить для предков, находящихся выше по дереву.

Из этой модели следует несколько выводов:

  • Компонент должен быть источником истины для вложенных компонентов в его shadow DOM. Вложенные компоненты не должны задавать свойства или вызывать методы своего компонента-хозяина.

  • Если компонент изменяет собственное публичное свойство, ему следует отправить событие, чтобы уведомить компоненты выше по дереву. Как правило, такие изменения происходят в результате действий пользователя — например, нажатия кнопки или выбора пункта меню. Вспомните встроенный элемент input: он отправляет событие, когда пользователь изменяет значение поля ввода.

Рассмотрим компонент меню, который содержит набор пунктов меню и предоставляет свойства items и selectedItem в рамках своего публичного API. Его структура DOM может выглядеть так:

A hierarchy of DOM nodes representing a menu. The top node, my-menu, has a ShadowRoot, which contains three my-item elements.

Когда пользователь выбирает пункт, элемент my-menu должен обновить своё свойство selectedItem. Ему также следует отправить событие, чтобы уведомить компонент-владелец об изменении выбора. Полная последовательность действий будет выглядеть примерно так:

  • Пользователь взаимодействует с пунктом, вызывая отправку события (стандартного, например click, или специфичного для компонента my-item).
  • Элемент my-menu получает событие и обновляет своё свойство selectedItem. Он также может изменить состояние, чтобы выделить выбранный пункт.
  • Элемент my-menu отправляет семантическое событие, указывающее на изменение выбора. Например, это событие может называться selected-item-changed. Поскольку это событие входит в API компонента my-menu, оно должно иметь понятный семантический смысл в этом контексте.

Подробнее об отправке событий и прослушивании событий см. в разделе События.

Передача данных между ветвями дерева

Правило «свойства вниз, события вверх» — хорошая отправная точка. Но что делать, если нужно обмениваться данными между двумя компонентами, которые не связаны отношением родителя и потомка напрямую? Например, между двумя компонентами-соседями в дереве теневого DOM?

Одно из решений этой проблемы — использовать шаблон посредника. В шаблоне посредника одноранговые компоненты не взаимодействуют друг с другом напрямую. Вместо этого их взаимодействия опосредованы третьей стороной.

Простой способ реализовать шаблон посредника — поручить компоненту-владельцу обрабатывать события от дочерних компонентов и при необходимости обновлять их состояние, передавая изменённые данные обратно вниз по дереву. Добавив посредника, вы сможете передавать данные между ветвями дерева, используя знакомый принцип «события вверх, свойства вниз».

В следующем примере элемент-посредник прослушивает события элементов input и button в своём shadow DOM. Он управляет состоянием доступности кнопки, чтобы пользователь мог нажать Отправить, только если в поле ввода есть текст.

К другим вариантам шаблона посредника относятся шаблоны в стиле Flux/Redux, где хранилище служит посредником для изменений и обновляет компоненты через подписки. Прямая подписка компонентов на изменения позволяет избежать необходимости передавать через каждый родительский компонент все данные, необходимые его дочерним компонентам.

Дочерние элементы Light DOM

Помимо узлов в shadow DOM, можно отображать дочерние узлы, предоставленные пользователем компонента. Например, стандартный элемент <select> может принимать набор элементов <option> в качестве дочерних и отображать их как пункты меню.

Дочерние узлы иногда называют «light DOM», чтобы отличать их от shadow DOM компонента. Например:

<top-bar>
  <icon-button icon="menu" slot="nav-button"></icon-button>
  <span slot="title">Fuzzy</span>
</top-bar>

Здесь элемент top-bar имеет два дочерних элемента light DOM, предоставленных пользователем: кнопку навигации и заголовок.

Взаимодействие с дочерними элементами light DOM отличается от взаимодействия с узлами shadow DOM. Узлами в shadow DOM компонента управляет сам компонент, и к ним не следует обращаться извне. Дочерними элементами light DOM управляют извне, но компонент тоже может к ним обращаться. Пользователь компонента может в любой момент добавлять или удалять дочерние элементы light DOM, поэтому компонент не может рассчитывать на неизменный набор дочерних узлов.

Компонент может управлять тем, будут ли дочерние узлы отображаться и где именно, используя элемент <slot> в своём shadow DOM. Компонент также может получать уведомления о добавлении и удалении дочерних узлов, прослушивая событие slotchange.

Подробнее см. разделы Отображение дочерних элементов с помощью слотов и Доступ к дочерним элементам, назначенным слотам.

Фото суриката: Anggit Rizkianto, Unsplash.

Изменить эту страницу

© Google LLC
Licensed under the Creative Commons Attribution 3.0 Unported License.
https://lit.dev/docs/v2/composition/component-composition/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API