December 15

Модульные веб-компоненты

Вложение (один веб-компонент внутри другого через <slot>) — это стандартный и очень мощный способ построения интерфейсов. Он отлично работает и является основой модульного дизайна веб-компонентов.

Вот как это будет работать.

Как элементы будут адресоваться в DOM.

1. Как будет выглядеть HTML-структура

Представим два компонента: ui-card (карточка-контейнер) и user-avatar (аватарка пользователя).

Разметка на странице (Light DOM):

html

<ui-card>
    <h2>Профиль пользователя</h2>
    <!-- Вложенный веб-компонент, который станет содержимым слота -->
    <user-avatar user-id="123"></user-avatar>
</ui-card>

Use code with caution.

2. Как это работает с точки зрения Shadow DOM и слотов

Когда браузер рендерит ui-card, он берет содержимое (включая user-avatar) и перенаправляет его туда, где находится <slot> внутри Shadow DOM компонента ui-card.

Внутреннее устройство ui-card (Shadow DOM):

html

<!-- Это Shadow DOM компонента ui-card -->
<div class="card-wrapper">
    <slot name="header"></slot> <!-- Сюда пойдет h2, если задать ему slot="header" -->
    <div class="body">
        <!-- А сюда пойдет все остальное содержимое, включая user-avatar -->
        <slot></slot> 
    </div>
</div>

Use code with caution.

Визуальный результат в браузере:

В конечном счете, компонент user-avatar отображается внутри визуальной области компонента ui-card, но он сохраняет свой собственный контекст DOM и свою собственную функциональность веб-компонента.

3. Адресация и доступ через DOM

Это ключевой момент. Вложенный веб-компонент (user-avatar) сохраняет свое место в Light DOM родительской страницы, а не перемещается физически в Shadow DOM. Слот — это лишь точка вставки (placeholder).

Доступ из родительской страницы (Light DOM)

Вы обращаетесь к вложенному компоненту как обычному элементу на странице:

javascript

// Отлично работает, так как элемент находится в основном DOM
const avatar = document.querySelector('user-avatar');
avatar.setUserId(456); 

Доступ из родительского компонента (ui-card)

Доступ к элементам, которые вставлены через слоты, требует использования специального API:

javascript

// В JavaScript компонента ui-card:
const slot = this.shadowRoot.querySelector('slot');

// Получаем массив всех "вставленных" элементов
const assignedElements = slot.assignedElements(); 

// Ищем конкретно наш вложенный компонент в этом массиве
const userAvatarComponent = assignedElements.find(el => el.tagName === 'USER-AVATAR');

if (userAvatarComponent) {
    userAvatarComponent.setUserId(789);
}

Use code with caution.

Доступ из вложенного компонента (user-avatar)

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

javascript

// В JavaScript компонента user-avatar
this.addEventListener('click', () => {
    console.log('Клик по аватару!');
    // Он может найти своего непосредственного родителя в Light DOM (это будет <ui-card>)
    console.log(this.parentElement); 
});

Use code with caution.

Резюме

  • Работает: Да, отлично работает.
  • Инкапсуляция: Каждый компонент полностью инкапсулирован своим Shadow DOM и логикой.
  • Адресация: Вложенный компонент остается в Light DOM, и к нему можно получить доступ как из основного скрипта страницы, так и из родительского компонента через API слотов (assignedElements()).