Слоты и распределение контента

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


Основы работы со слотами

В SkateJS слоты работают аналогично стандартным веб-компонентам с <slot>. Любой элемент внутри компонента, который не соответствует специфической точке распределения (слоту), автоматически помещается в default slot. Простейший пример:

import { define, Component, h } from 'skatejs';

class Card extends Component {
  renderCallback() {
    return (
      <div class="card">
        <header>
          <slot name="header"></slot>
        </header>
        <main>
          <slot></slot>
        </main>
        <footer>
          <slot name="footer"></slot>
        </footer>
      </div>
    );
  }
}

define('my-card', Card);

В этом примере определены три слота:

  • header — именованный слот для заголовка.
  • footer — именованный слот для подвала.
  • default slot — основной слот, куда попадет остальной контент.

Использование компонента может выглядеть так:

<my-card>
  <h1 slot="header">Заголовок</h1>
  <p>Основной контент карточки</p>
  <button slot="footer">Нажми меня</button>
</my-card>

Элементы автоматически распределяются по слотам на основе атрибута slot. Контент без указания имени помещается в default slot.


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

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

Default slot не требует имени. Любой элемент без атрибута slot попадет именно туда. Если default slot отсутствует, такие элементы игнорируются в распределении.

Важно помнить:

  • Наличие нескольких элементов с одним именем слота приводит к последовательному рендерингу всех элементов в этом слоте.
  • Атрибут slot на компоненте может быть динамическим, что позволяет менять расположение контента в зависимости от состояния.

Динамическое распределение контента

SkateJS позволяет изменять содержимое слотов программно, используя children и assignedNodes():

class DynamicCard extends Component {
  renderCallback() {
    return (
      <div>
        <slot name="dynamic"></slot>
      </div>
    );
  }

  connectedCallback() {
    super.connectedCallback();
    const slot = this.shadowRoot.querySelector('slot[name="dynamic"]');
    slot.addEventListener('slotchange', () => {
      const nodes = slot.assignedNodes({ flatten: true });
      console.log('Контент слота обновлен:', nodes);
    });
  }
}

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


Слоты и реактивные свойства

SkateJS интегрирует слоты с реактивной системой компонентов. Изменение содержимого слота может автоматически вызывать обновление рендеринга или триггерить вычисляемые свойства:

class StatusCard extends Component {
  static props = {
    hasContent: { type: Boolean }
  };

  renderCallback() {
    return (
      <div>
        <slot onSlotcha nge={() => this.hasContent = this.shadowRoot.querySelector('slot').assignedNodes().length > 0}></slot>
        {this.hasContent ? <p>Контент доступен</p> : <p>Контент отсутствует</p>}
      </div>
    );
  }
}

Событие slotchange обеспечивает реакцию компонента на изменения распределенного контента.


Вложенные слоты

В SkateJS слоты могут быть вложенными, что позволяет создавать сложные компоненты с несколькими уровнями распределения. Например, карточка с вкладками:

class TabPanel extends Component {
  renderCallback() {
    return (
      <div class="tab-panel">
        <nav>
          <slot name="tabs"></slot>
        </nav>
        <section>
          <slot name="content"></slot>
        </section>
      </div>
    );
  }
}

Элементы с slot="tabs" и slot="content" могут содержать свои собственные слоты, позволяя организовать многоуровневую структуру без потери контроля над содержимым.


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

  • Использовать default slot только для основного контента. Именованные слоты делают код более читаемым и предсказуемым.
  • Обрабатывать события slotchange для динамических компонентов, чтобы отслеживать добавление или удаление контента.
  • Не смешивать слишком много уровней вложенности, чтобы не усложнять распределение и рендеринг.
  • Документировать слоты при создании библиотеки компонентов, чтобы пользователи понимали, какой контент куда помещать.

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