Доступ к содержимому слотов

Slim.js — легковесная библиотека для создания веб-компонентов с реактивными свойствами и декларативной разметкой. Одной из ключевых возможностей при работе с компонентами является использование слотов, которые позволяют гибко вставлять контент внутрь компонентов и управлять его отображением.

Основы слотов

Слот — это специальный элемент <slot> внутри шаблона компонента, который служит местом для вставки внешнего контента. Контент, переданный в слот, называется assigned nodes. Slim.js поддерживает как обычные, так и именованные слоты.

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

class MyComponent extends Slim {
  get template() {
    return `
      <div>
        <h2>Заголовок компонента</h2>
        <slot></slot>
      </div>
    `;
  }
}
customElements.define('my-component', MyComponent);

HTML:

<my-component>
  <p>Вставленный контент</p>
</my-component>

В результате <p>Вставленный контент</p> появится на месте <slot>.

Именованные слоты

Для управления несколькими зонами вставки используется имя слота через атрибут name:

class CardComponent extends Slim {
  get template() {
    return `
      <div class="card">
        <header><slot name="header"></slot></header>
        <main><slot></slot></main>
        <footer><slot name="footer"></slot></footer>
      </div>
    `;
  }
}
customElements.define('card-component', CardComponent);

HTML:

<card-component>
  <h1 slot="header">Заголовок карточки</h1>
  <p>Основной контент</p>
  <button slot="footer">Закрыть</button>
</card-component>

В этом случае <slot> без имени используется для основного контента, а именованные слоты — для отдельных частей шаблона.

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

Для работы с контентом слота в коде компонента применяется свойство this.shadowRoot и методы querySelector или querySelectorAll для слота, а также assignedNodes() или assignedElements() для получения переданного содержимого.

Пример:

class SlotInspector extends Slim {
  get template() {
    return `
      <div>
        <slot></slot>
        <button id="inspect">Показать содержимое слота</button>
      </div>
    `;
  }

  onBeforeCreated() {
    this.handleClick = () => {
      const slot = this.shadowRoot.querySelector('slot');
      const nodes = slot.assignedNodes({ flatten: true });
      console.log(nodes);
    };
  }

  onCreated() {
    this.shadowRoot.getElementById('inspect')
      .addEventListener('click', this.handleClick);
  }
}
customElements.define('slot-inspector', SlotInspector);

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

Реактивность слотов

Slim.js поддерживает реактивность через слоты, но изменения контента, переданного извне, не вызывают автоматическое обновление состояния компонента. Для отслеживания динамических изменений применяются события slotchange.

class DynamicSlot extends Slim {
  get template() {
    return `<slot></slot>`;
  }

  onCreated() {
    const slot = this.shadowRoot.querySelector('slot');
    slot.addEventListener('slotchange', () => {
      console.log('Содержимое слота изменилось:', slot.assignedNodes());
    });
  }
}
customElements.define('dynamic-slot', DynamicSlot);

Событие slotchange срабатывает при добавлении, удалении или изменении узлов в слоте, что позволяет реализовать реактивное поведение без дополнительных библиотек.

Фильтрация и обработка содержимого слота

Для сложных компонентов часто требуется фильтровать или модифицировать узлы слота перед использованием:

const slot = this.shadowRoot.querySelector('slot');
const elements = slot.assignedElements().filter(el => el.tagName === 'LI');
elements.forEach(el => el.style.color = 'blue');

Таким образом можно применять стили, изменять свойства или связывать события только с определёнными элементами.

Использование слотов с шаблонами Slim.js

Slim.js позволяет комбинировать слоты с реактивными свойствами и циклическими конструкциями:

class ListWrapper extends Slim {
  items = ['Элемент 1', 'Элемент 2', 'Элемент 3'];

  get template() {
    return `
      <ul>
        <slot></slot>
        ${this.items.map(item => `<li>${item}</li>`).join('')}
      </ul>
    `;
  }
}
customElements.define('list-wrapper', ListWrapper);

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

Резюме ключевых методов

  • slot.assignedNodes({ flatten: true }) — возвращает все узлы, назначенные слоту, включая текстовые.
  • slot.assignedElements() — возвращает только элементные узлы.
  • slot.addEventListener('slotchange', callback) — отслеживает изменения содержимого слота.
  • Атрибут name у <slot> и slot у дочернего элемента — управление именованными слотами.

Эти инструменты дают полный контроль над содержимым слотов, обеспечивая гибкость при построении сложных веб-компонентов в Slim.js.