{#snippet ...}
{#snippet name()}...{/snippet}
{#snippet name(param1, param2, paramN)}...{/snippet}
Фрагменты и теги render — это способ создавать многократно используемые блоки разметки внутри ваших компонентов. Вместо того чтобы писать повторяющийся код, как здесь…
{#each images as image} {#if image.href} <a href={image.href}> <figure> <img src={image.src} alt={image.caption} width={image.width} height={image.height} /> <figcaption>{image.caption}</figcaption> </figure> </a> {:else} <figure> <img src={image.src} alt={image.caption} width={image.width} height={image.height} /> <figcaption>{image.caption}</figcaption> </figure> {/if}{/each}
…вы можете писать это:
{#snippet figure(image)} <figure> <img src={image.src} alt={image.caption} width={image.width} height={image.height} /> <figcaption>{image.caption}</figcaption> </figure>{/snippet}
{#each images as image} {#if image.href} <a href={image.href}> {@render figure(image)} </a> {:else} {@render figure(image)} {/if}{/each}
Как и функции, фрагменты могут принимать любое количество параметров, у которых могут быть значения по умолчанию, и вы можете деструктурировать эти параметры. Однако вы не можете использовать остаточные параметры (rest).
Область видимости фрагментов
Заголовок раздела «Область видимости фрагментов»Фрагменты могут быть объявлены в любом месте внутри вашего компонента. Они могут ссылаться на значения, объявленные вне их самих, например, в теге <script>
или в блоках {#each ...}
(демонстрация)…
<script> let { message = `Приятно тебя видеть!` } = $props();</script>
{#snippet hello(name)} <p>Привет, {name}! {message}!</p>{/snippet}
{@render hello('alice')}{@render hello('bob')}
…и они «видимы» для всего в той же области видимости (то есть для соседних элементов и их потомков):
<div> {#snippet x()} {#snippet y()}...{/snippet}
<!-- это сработает --> {@render y()} {/snippet}
<!-- это вызовет ошибку, так как `y` не находится в области видимости --> {@render y()}</div>
<!-- это также вызовет ошибку, так как `x` не находится в области видимости -->{@render x()}
Фрагменты могут ссылаться на себя и друг на друга (демонстрация):
{#snippet blastoff()} <span>🚀</span>{/snippet}
{#snippet countdown(n)} {#if n > 0} <span>{n}...</span> {@render countdown(n - 1)} {:else} {@render blastoff()} {/if}{/snippet}
{@render countdown(10)}
Передача фрагментов в компоненты
Заголовок раздела «Передача фрагментов в компоненты»Явные пропсы
Заголовок раздела «Явные пропсы»Внутри шаблона фрагменты являются значениями, как и любые другие. Следовательно, их можно передавать в компоненты как пропсы (демонстрация):
<script> import Table from './Table.svelte';
const fruits = [ { name: 'apples', qty: 5, price: 2 }, { name: 'bananas', qty: 10, price: 1 }, { name: 'cherries', qty: 20, price: 0.5 } ];</script>
{#snippet header()} <th>fruit</th> <th>qty</th> <th>price</th> <th>total</th>{/snippet}
{#snippet row(d)} <td>{d.name}</td> <td>{d.qty}</td> <td>{d.price}</td> <td>{d.qty * d.price}</td>{/snippet}
<Table data={fruits} {header} {row} />
Думайте об этом как о передаче содержимого, а не данных, в компонент. Концепция похожа на слоты в веб-компонентах.
Неявные пропсы
Заголовок раздела «Неявные пропсы»Для удобства написания кода фрагменты, определённые внутри компонента, автоматически обрабатываются как пропсы этого компонента (демонстрация):
<!-- это семантически то же самое, что и выше --><Table data={fruits}> {#snippet header()} <th>fruit</th> <th>qty</th> <th>price</th> <th>total</th> {/snippet}
{#snippet row(d)} <td>{d.name}</td> <td>{d.qty}</td> <td>{d.price}</td> <td>{d.qty * d.price}</td> {/snippet}</Table>
Неявный фрагмент children
Заголовок раздела «Неявный фрагмент children»Любой контент внутри тегов компонента, который не является объявлением фрагмента, неявно становится частью фрагмента children
(демонстрация):
<Button>нажми меня</Button>
<script> let { children } = $props();</script>
<!-- Результатом будет <button>нажми меня</button> --><button>{@render children()}</button>
<script lang="ts"> let { children } = $props();</script>
<!-- Результатом будет <button>нажми меня</button> --><button>{@render children()}</button>
Необязательные пропсы фрагментов
Заголовок раздела «Необязательные пропсы фрагментов»Вы можете объявить пропсы фрагментов как необязательные. Используйте опциональную цепочку, чтобы не отображать ничего, если фрагмент не задан…
<script> let { children } = $props();</script>
{@render children?.()}
…или используйте блок #if
, чтобы отобразить альтернативный контент:
<script> let { children } = $props();</script>
{#if children} {@render children()}{:else} альтернативный контент{/if}
Типизация фрагментов
Заголовок раздела «Типизация фрагментов»Фрагменты реализуют интерфейс Snippet
, импортируемый из 'svelte'
:
<script lang="ts"> import type { Snippet } from 'svelte';
interface Props { data: any[]; children: Snippet; row: Snippet<[any]>; }
let { data, children, row }: Props = $props();</script>
С этим изменением появятся красные волнистые линии, если вы попытаетесь использовать компонент без предоставления пропа data
и фрагмента row
. Обратите внимание, что аргумент типа, переданный в Snippet
, является кортежем, так как фрагменты могут иметь несколько параметров.
Мы можем ещё больше улучшить типизацию, объявив универсальный тип, чтобы data
и row
ссылались на один и тот же тип:
<script lang="ts" generics="T"> import type { Snippet } from 'svelte';
let { data, children, row }: { data: T[]; children: Snippet; row: Snippet<[T]>; } = $props();</script>
Экспорт фрагментов
Заголовок раздела «Экспорт фрагментов»Фрагменты, объявленные на верхнем уровне файла .svelte
, могут быть экспортированы из <script module>
для использования в других компонентах, при условии, что они не ссылаются на объявления в не-модульном <script>
(непосредственно или косвенно через другие фрагменты) (демонстрация):
<script module> export { add };</script>
{#snippet add(a, b)} {a} + {b} = {a + b}{/snippet}
Программные фрагменты
Заголовок раздела «Программные фрагменты»Фрагменты могут быть созданы программно с помощью API createRawSnippet
. Это предназначено для продвинутых случаев использования.
Фрагменты и слоты
Заголовок раздела «Фрагменты и слоты»В Svelte 4 контент можно передавать в компоненты с использованием слотов. Фрагменты более мощные и гибкие, поэтому слоты устарели в Svelte 5.