Слоты и проекция контента

Фреймворк Polymer предоставляет мощный механизм для создания веб-компонентов с возможностью гибкой проекции контента. Основной инструмент для этого — слоты. С их помощью можно управлять тем, как внешний контент вставляется внутрь компонентов, сохраняя инкапсуляцию и повторное использование элементов.


Определение слотов

Слот — это место внутри веб-компонента, куда может быть вставлен внешний контент. В Polymer слоты реализуются с помощью элемента <slot>. Любой элемент, помещённый в компонент с указанием слота, автоматически проецируется в соответствующее место.

Простейший пример:

<my-card>
  <h1 slot="title">Заголовок карточки</h1>
  <p>Описание карточки</p>
</my-card>

Компонент my-card может быть описан так:

import { PolymerElement, html } from '@polymer/polymer/polymer-element.js';

class MyCard extends PolymerElement {
  static get template() {
    return html`
      <div class="card">
        <header>
          <slot name="title"></slot>
        </header>
        <main>
          <slot></slot>
        </main>
      </div>
    `;
  }
}

customElements.define('my-card', MyCard);

Здесь:

  • <slot name="title"></slot> проецирует содержимое с атрибутом slot="title".
  • <slot></slot> без имени — это дефолтный слот, куда попадает контент без указания имени.

Типы слотов

  1. Дефолтные слоты Используются для проекции контента без явного указания имени.

    <slot></slot>

    Вставленный в компонент элемент без атрибута slot попадёт именно сюда.

  2. Именованные слоты Позволяют точно управлять размещением контента.

    <slot name="footer"></slot>

    Контент проецируется только если у него задано slot="footer".


Поведение слотов

  • Если слот пустой, он может содержать дефолтный контент, который отображается, когда внешний контент не предоставлен:
<slot>
  <p>Содержимое по умолчанию</p>
</slot>
  • Проекция динамического контента поддерживается. Polymer автоматически обновляет DOM при изменении содержимого компонента.

Доступ к слотам через JavaScript

Polymer предоставляет API для работы с содержимым слотов:

const slot = this.shadowRoot.querySelector('slot[name="title"]');
const assignedNodes = slot.assignedNodes({flatten: true});

Метод assignedNodes() возвращает все узлы, которые проецируются в слот, включая текстовые и элементные узлы. Параметр {flatten: true} учитывает вложенные слоты.

С помощью этого механизма можно:

  • Изменять проецируемый контент программно.
  • Реагировать на события изменения слота (slotchange):
slot.addEventListener('slotchange', (e) => {
  console.log('Содержимое слота изменено', slot.assignedNodes());
});

Вложенные слоты и составные компоненты

Слоты позволяют строить многоуровневые компоненты, где один компонент проецирует контент другого. Пример:

<parent-component>
  <child-component slot="header">
    <p>Заголовок ребенка</p>
  </child-component>
</parent-component>

В parent-component можно иметь слот header, а child-component внутри тоже может использовать свои слоты. Polymer корректно распределяет контент, сохраняя структуру DOM.


Практические рекомендации

  • Всегда использовать именованные слоты, если компонент предполагает несколько областей для контента. Это делает структуру читаемой.
  • Для динамических интерфейсов слоты позволяют легко заменять части компонента без переписывания шаблона.
  • Обработка события slotchange полезна для реактивного обновления состояния компонента при изменении проецируемого контента.

Примеры использования

Карточка с заголовком и подвалом:

<my-card>
  <h1 slot="title">Новости дня</h1>
  <p>Главные события сегодня...</p>
  <footer slot="footer">Источник: news.com</footer>
</my-card>

Шаблон компонента:

class MyCard extends PolymerElement {
  static get template() {
    return html`
      <div class="card">
        <header><slot name="title"></slot></header>
        <main><slot></slot></main>
        <footer><slot name="footer">Подвал по умолчанию</slot></footer>
      </div>
    `;
  }
}

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


С помощью слотов Polymer реализует концепцию content projection, позволяя разработчикам создавать сложные, динамические интерфейсы без нарушения инкапсуляции компонентов. Это один из ключевых механизмов, обеспечивающих гибкость веб-компонентов.