{#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.