Слоты и композиция компонентов

Слоты в SvelteKit позволяют создавать компоненты с гибкой структурой, где часть содержимого может быть передана извне. Это ключевой инструмент для композиции UI, особенно при разработке библиотек компонентов, где один и тот же каркас может использоваться с разным контентом.

В Svelte слоты задаются через <slot> внутри компонента:

<!-- Card.svelte -->
<div class="card">
  <slot></slot>
</div>

Использование:

<Card>
  <h2>Заголовок карточки</h2>
  <p>Описание содержимого карточки.</p>
</Card>

В этом примере весь переданный контент будет вставлен внутрь <div class="card">.


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

Именованные слоты позволяют вставлять контент в конкретные области компонента. Это особенно полезно, когда компонент имеет несколько зон с разной семантикой.

<!-- Modal.svelte -->
<div class="modal">
  <header><slot name="header"></slot></header>
  <main><slot></slot></main>
  <footer><slot name="footer"></slot></footer>
</div>

Использование именованных слотов:

<Modal>
  <h1 slot="header">Заголовок модального окна</h1>
  <p>Основной контент окна.</p>
  <button slot="footer">Закрыть</button>
</Modal>

Если контент для именованного слота не передан, можно задать контент по умолчанию:

<header><slot name="header">Стандартный заголовок</slot></header>

Пропсы слотов (Slot Props)

Слоты могут принимать данные из родительского компонента через slot props. Это позволяет создавать компоненты с динамическим содержимым, где внутренняя логика компонента управляет передаваемыми данными.

<!-- Dropdown.svelte -->
<script>
  export let items = [];
</script>

<ul>
  {#each items as item}
    <li><slot {item}>{item.name}</slot></li>
  {/each}
</ul>

Использование с доступом к slot props:

<Dropdown items="{[{name: 'One'}, {name: 'Two'}]}">
  <span let:item>{item.name.toUpperCase()}</span>
</Dropdown>

Здесь let:item связывает локальную переменную с пропом слота, предоставленным компонентом.


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

Композиция — это создание сложных компонентов из более простых. В SvelteKit это особенно важно при разработке UI библиотек, где повторное использование элементов критично.

Вложенные компоненты

Компоненты могут включать друг друга, используя слоты и пропсы для передачи данных:

<!-- Form.svelte -->
<form on:submit|preventDefault={handleSubmit}>
  <slot></slot>
</form>

<script>
  function handleSubmit() {
    console.log("Форма отправлена");
  }
</script>
<Form>
  <input type="text" placeholder="Имя" />
  <button type="submit">Отправить</button>
</Form>

Высокоуровневая композиция

Можно строить компоненты, комбинируя несколько вложенных элементов с именованными слотами:

<!-- PageLayout.svelte -->
<header><slot name="header"></slot></header>
<aside><slot name="sidebar"></slot></aside>
<main><slot></slot></main>
<footer><slot name="footer"></slot></footer>

Использование:

<PageLayout>
  <nav slot="header">Навигация</nav>
  <aside slot="sidebar">Меню</aside>
  <p>Основной контент страницы</p>
  <footer slot="footer">Футер</footer>
</PageLayout>

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


Динамические слоты и условная композиция

Слоты можно использовать динамически, например, менять содержимое в зависимости от состояния:

<Modal>
  {#if user.isLoggedIn}
    <p slot="header">Добро пожаловать, {user.name}</p>
  {:else}
    <p slot="header">Пожалуйста, войдите</p>
  {/if}
</Modal>

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


Практические советы по работе с UI библиотеками

  1. Минимизировать дублирование кода: используйте слоты для областей, где контент меняется часто, но структура компонента остаётся неизменной.
  2. Комбинировать именованные и обычные слоты для сложных компонентов, чтобы различать основной контент и вспомогательные блоки.
  3. Использовать slot props для передачи данных внутрь слотов, сохраняя компонент универсальным.
  4. Следовать принципу “одна ответственность на компонент”: компонент должен управлять только своей структурой и стилем, а содержимое передавать через слоты.

Итоговая архитектура

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

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