Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Вложенное содержимое и сниппеты

Иногда компоненту нужно передать не данные, а целый кусок разметки: карточка с произвольным содержимым, список, в котором родитель решает, как выглядит строка. В Svelte 5 такой кусок разметки называется сниппетом (snippet), а выводится он тегом {@render}.

Содержимое между тегами

Всё, что родитель пишет между открывающим и закрывающим тегом компонента, приходит в свойство children. Создайте файл src/lib/components/Card.svelte:

<!-- src/lib/components/Card.svelte -->
<script>
  let { children } = $props();
</script>
 
<section class="card">
  {@render children()}
</section>
 
<style>
  .card {
    border: 1px solid #ddd;
    border-radius: 8px;
    padding: 16px;
  }
</style>

Компонент рисует рамку, а внутрь выводит то, что ему передали.

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

<!-- src/routes/+page.svelte -->
<script>
  import Card from '$lib/components/Card.svelte';
</script>
 
<Card>
  <h2>Мои задачи</h2>
  <p>Задач на сегодня: 3</p>
</Card>

На странице появится рамка со скруглёнными углами, а в ней заголовок и абзац. Один компонент Card подойдёт для любого содержимого.

Если содержимого нет

Если вызвать <Card /> без содержимого, children будет undefined, и children() вызовет ошибку. Для необязательного содержимого используйте вызов с ?.:

<!-- src/lib/components/Card.svelte -->
<script>
  let { children } = $props();
</script>
 
<section class="card">
  {@render children?.()}
</section>

Свой сниппет с параметром

Сниппет можно объявить и вручную блоком {#snippet имя(параметры)}. Объявленный внутри тега компонента, он становится свойством с тем же именем. Сделаем список, в котором родитель решает, как выглядит строка:

<!-- src/lib/components/TodoList.svelte -->
<script>
  let { todos, row } = $props();
</script>
 
<ul>
  {#each todos as todo (todo.id)}
    <li>{@render row(todo)}</li>
  {/each}
</ul>
<!-- src/routes/+page.svelte -->
<script>
  import TodoList from '$lib/components/TodoList.svelte';
 
  let todos = $state([
    { id: 1, text: 'Купить хлеб', done: true },
    { id: 2, text: 'Позвонить Олегу', done: false }
  ]);
</script>
 
<TodoList {todos}>
  {#snippet row(todo)}
    <strong>{todo.done ? '✓' : '○'}</strong> {todo.text}
  {/snippet}
</TodoList>

TodoList перебирает задачи и для каждой вызывает сниппет row, передавая ему задачу. Вид строки при этом задаёт страница: жирная отметка и текст.

Сниппет внутри одного компонента

Сниппет, объявленный в обычной разметке, можно вызывать несколько раз в том же файле — это способ не повторять одинаковый кусок разметки без отдельного компонента.

Частая ошибка

Выводить сниппет фигурными скобками без @render: {children} или {row(todo)}. Сниппет — функция особого вида, а не строка, поэтому на странице ничего полезного не появится. Сниппеты всегда выводят тегом {@render ...}.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.