{#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}
像函式宣告一樣,程式碼片段可以有任意數量的參數,這些參數可以有預設值,並且您可以解構每個參數。但是,您不能使用剩餘參數。
程式碼片段範圍
程式碼片段可以在元件內的任何位置宣告。它們可以參考在自身之外宣告的值,例如在 <script>
標籤中或在 {#each ...}
區塊中(範例)...
<script>
let { message = `it's great to see you!` } = $props();
</script>
{#snippet hello(name)}
<p>hello {name}! {message}!</p>
{/snippet}
{@render hello('alice')}
{@render hello('bob')}
...並且它們對相同語彙範圍內的所有事物(即兄弟姐妹,以及這些兄弟姐妹的子節點)「可見」。
<div>
{#snippet x()}
{#snippet y()}...{/snippet}
<!-- this is fine -->
{@render y()}
{/snippet}
<!-- this will error, as `y` is not in scope -->
{@render y()}
</div>
<!-- this will also error, as `x` is not in scope -->
{@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)}
將程式碼片段傳遞給元件
在樣板中,程式碼片段就像任何其他值一樣。因此,它們可以作為 props 傳遞給元件(範例)
<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} />
把它想像成將內容而不是資料傳遞給元件。這個概念類似於網頁元件中的插槽。
為了方便撰寫,直接在元件內宣告的程式碼片段會隱式地成為元件上的 props(範例)
<!-- this is semantically the same as the above -->
<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
程式碼片段的一部分(範例)
<Button>click me</Button>
<script>
let { children } = $props();
</script>
<!-- result will be <button>click me</button> -->
<button>{@render children()}</button>
請注意,如果您在元件內有內容,則不能有稱為
children
的 prop - 因此,您應避免使用該名稱的 props
您可以宣告程式碼片段 props 為可選。您可以使用可選鏈來在未設定程式碼片段時不渲染任何內容...
<script>
let { children } = $props();
</script>
{@render children?.()}
...或使用 #if
區塊來渲染回退內容
<script>
let { children } = $props();
</script>
{#if children}
{@render children()}
{:else}
fallback content
{/if}
類型化程式碼片段
程式碼片段實作從 'svelte'
匯入的 Snippet
介面
<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
prop 和 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}
這需要 Svelte 5.5.0 或更新版本
程式化程式碼片段
可以使用 createRawSnippet
API 以程式化的方式建立程式碼片段。這適用於進階使用案例。
程式碼片段和插槽
在 Svelte 4 中,可以使用 插槽將內容傳遞給元件。程式碼片段功能更強大且更靈活,因此插槽在 Svelte 5 中已棄用。