Перейти к содержимому

31. Slots и именованные слоты

Слоты — это механизм передачи контента в компонент снаружи. Аналог children в React, но значительно мощнее: Astro поддерживает именованные слоты, фолбэки и проверку наличия контента.

Самый простой случай — компонент, который оборачивает любой контент:

Card.astro
<div class="card">
<slot />
</div>
---
import Card from './Card.astro';
---
<Card>
<p>Этот текст попадёт в слот</p>
</Card>

Если нужно несколько мест для контента, используйте именованные слоты:

BlogCard.astro
<article class="blog-card">
<header>
<slot name="header" />
</header>
<div class="body">
<slot />
</div>
<footer>
<slot name="footer" />
</footer>
</article>
<BlogCard>
<h2 slot="header">Заголовок статьи</h2>
<p>Основной текст статьи...</p>
<button slot="footer">Читать далее</button>
</BlogCard>

Если слот не заполнен — отображается фолбэк:

<div class="card">
<slot name="header">
<!-- Показывается, если header не передан -->
<h3>Заголовок по умолчанию</h3>
</slot>
<slot>
<p>Контент не предоставлен</p>
</slot>
</div>

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

---
const hasFooter = Astro.slots.has('footer');
const hasSidebar = Astro.slots.has('sidebar');
---
<div class:list={['layout', { 'with-sidebar': hasSidebar }]}>
<main>
<slot />
</main>
{hasSidebar && (
<aside>
<slot name="sidebar" />
</aside>
)}
{hasFooter && (
<footer>
<slot name="footer" />
</footer>
)}
</div>

Можно получить HTML слота как строку:

---
const headerContent = await Astro.slots.render('header');
---
<div data-has-header={!!headerContent}>
<Fragment set:html={headerContent} />
</div>

Astro поддерживает передачу данных из компонента в переданный контент:

List.astro
---
const items = ['apple', 'banana', 'cherry'];
---
<ul>
{items.map((item) => (
<slot name="item" item={item} />
))}
</ul>

Самое распространённое применение — лейаут-компоненты:

BaseLayout.astro
---
const { title } = Astro.props;
---
<!DOCTYPE html>
<html>
<head>
<title>{title}</title>
<slot name="head" />
</head>
<body>
<slot name="header">
<header>Шапка по умолчанию</header>
</slot>
<main>
<slot />
</main>
<slot name="footer">
<footer>Подвал по умолчанию</footer>
</slot>
</body>
</html>

Используйте слоты, когда передаёте:

  • HTML/компоненты (разметку)
  • Контент, который может меняться на каждой странице
  • Большие блоки текста

Используйте props, когда передаёте:

  • Примитивные значения (строки, числа, булевы)
  • Данные для вычислений внутри компонента
  • Конфигурацию поведения