В Svelte система слотов предоставляет мощный способ для создания гибких и повторно используемых компонентов, что позволяет строить композицию UI без необходимости жёстко задавать структуру компонентов. Слоты дают возможность вставлять контент из родительского компонента в дочерний, а также позволять дочерним компонентам управлять тем, как этот контент будет отображаться.
Слот в Svelte — это механизм, позволяющий передавать контент из
родительского компонента в дочерний. Он работает схоже с аналогичной
концепцией в веб-компонентах. В Svelte слот определяется внутри
дочернего компонента с помощью специального тега
<slot></slot>. Контент, который не будет
предоставлен родителем, может быть заменён по умолчанию.
Пример простого компонента с использованием слота:
<!-- Дочерний компонент -->
<div>
<h1>Заголовок компонента</h1>
<slot></slot> <!-- Здесь будет отображаться контент из родителя -->
</div>
В родительском компоненте можно вставить контент внутрь слота:
<!-- Родительский компонент -->
<ChildComponent>
<p>Этот текст будет вставлен в слот дочернего компонента</p>
</ChildComponent>
В результате, внутри дочернего компонента на месте тега
<slot></slot> будет отображён параграф из
родителя.
Помимо стандартного слота, Svelte поддерживает именованные слоты, что
позволяет передавать несколько различных частей контента в разные
области компонента. Для этого используется атрибут name,
который позволяет отличить слоты друг от друга.
Пример с несколькими слотами:
<!-- Дочерний компонент с несколькими слотами -->
<div>
<header>
<slot name="header"></slot> <!-- Слот для заголовка -->
</header>
<main>
<slot></slot> <!-- Основной слот -->
</main>
</div>
Родительский компонент может передавать контент в каждый из этих слотов с помощью соответствующих атрибутов:
<!-- Родительский компонент -->
<ChildComponent>
<h2 slot="header">Заголовок</h2> <!-- Контент для слота "header" -->
<p>Основной контент для слота</p> <!-- Контент для основного слота -->
</ChildComponent>
Таким образом, родительский компонент может управлять тем, какие части контента попадут в каждый конкретный слот дочернего компонента, что даёт высокую гибкость в работе с UI.
Если в слот не был передан контент, можно задать дефолтное значение,
которое будет отображаться по умолчанию. Для этого достаточно добавить
контент внутрь тега <slot></slot>.
Пример использования дефолтного контента:
<!-- Дочерний компонент -->
<div>
<slot>Это дефолтный контент, если родитель не передаст ничего</slot>
</div>
Если родитель не передаст контент для слота, то отобразится указанный дефолтный текст.
Svelte позволяет управлять содержимым слота на уровне программной логики, что даёт возможность не только передавать HTML, но и взаимодействовать с данными через слоты. Это особенно полезно, когда нужно предоставить родителю больше контроля над отображением контента, в том числе через условные рендеры или передаваемые состояния.
Пример динамического контента для слота:
<!-- Дочерний компонент -->
<div>
<slot {isLoggedIn}></slot>
</div>
<!-- Родительский компонент -->
<ChildComponent {isLoggedIn}>
{#if isLoggedIn}
<p>Добро пожаловать, пользователь!</p>
{:else}
<p>Пожалуйста, войдите в систему</p>
{/if}
</ChildComponent>
Здесь родитель передаёт в слот данные (isLoggedIn), и на
основе этих данных в дочернем компоненте выбирается, какой контент
отображать.
Слоты позволяют строить сложные интерфейсы, комбинируя несколько дочерних компонентов. Каждый дочерний компонент может иметь свои собственные слоты, которые могут быть заполнены родителями, создавая таким образом композицию компонентов на различных уровнях. Это особенно важно при проектировании крупных интерфейсов, где необходима гибкость и повторное использование элементов.
Пример композиции с несколькими уровнями слотов:
<!-- Дочерний компонент 1 -->
<div>
<header>
<slot name="header"></slot>
</header>
<section>
<slot></slot> <!-- Основной слот -->
</section>
</div>
<!-- Дочерний компонент 2 -->
<ChildComponent1>
<h2 slot="header">Заголовок от родителя</h2>
<p>Основной контент</p>
</ChildComponent1>
В этом примере один дочерний компонент используется в качестве контейнера для другого, что позволяет строить гибкие и вложенные компоненты с максимальным контролем над их содержимым.
Слоты в Svelte также могут быть использованы в динамических компонентах, где родительский компонент решает, какой дочерний компонент должен быть отрендерен в зависимости от состояния.
Пример динамической композиции:
<script>
let activeComponent = 'ComponentA';
</script>
<ChildComponent>
{#if activeComponent === 'ComponentA'}
<ComponentA slot="content" />
{:else}
<ComponentB slot="content" />
{/if}
</ChildComponent>
Здесь родительский компонент управляет тем, какой компонент будет
отображён внутри слота дочернего компонента, изменяя состояние
activeComponent. Такой подход даёт возможность создавать
гибкие и многоразовые компоненты с динамическим содержимым.
Композиция компонентов с помощью слотов в Svelte может быть усилена использованием контекстного API, которое позволяет передавать данные от родителя к дочерним компонентам без явной передачи через пропсы. Это особенно полезно, когда необходимо передать данные на несколько уровней вниз по дереву компонентов.
Пример контекста и слотов:
<!-- Родительский компонент -->
<script context="module">
import { setContext } from 'svelte';
setContext('user', { name: 'Иван' });
</script>
<ChildComponent />
<!-- Дочерний компонент -->
<script context="module">
import { getContext } from 'svelte';
const user = getContext('user');
</script>
<div>
<slot {user}></slot>
</div>
В этом примере данные о пользователе передаются в дочерний компонент через контекст, который может быть использован в слоте для отображения информации.
Слоты в Svelte — это мощный инструмент для создания гибких и масштабируемых интерфейсов. Они позволяют создавать компоненты, которые могут быть легко составлены из различных частей и адаптированы под различные нужды. Использование именованных слотов, дефолтных значений и контекстного API позволяет ещё больше повысить гибкость и возможность повторного использования компонентов, делая их более универсальными и эффективными в рамках сложных приложений.