首页 / Svelte 5 入门教程 / 声明标签(Declaration Tags)

Svelte 5 入门教程

声明标签(Declaration Tags)

本教程共 50 篇 · 第 17 篇 · 更新于 2026-08-05 · 约 6 分钟阅读

SvelteSvelte 5模板语法声明标签Declaration Tags

17. 声明标签(Declaration Tags)

本节目标:掌握 Svelte 5.56+ 引入的声明标签语法,学会在模板中用 {const} 和 {let} 声明变量和响应式状态。学完你能用更灵活的方式组织模板逻辑。

什么是声明标签

声明标签是 Svelte 5.56 引入的新特性,让你直接在模板标记中声明变量,不再局限于 <script> 标签内。

先看一个例子:

<script>
	let boxes = [
		{ width: 10, height: 10 },
		{ width: 15, height: 15 }
	];
</script>

{#each boxes as box}
	{const area = box.width * box.height}
	{const label = `${box.width} × ${box.height} = ${area}`}

	<p>{label}</p>
{/each}

注意这里用的是 {const area = ...} 而不是旧的 {@const area = ...}。少了那个 @ 符号,但能力更强了。

Note

声明标签从 Svelte 5.56 开始支持。如果你使用的是更早的版本,需要用旧语法 {@const}。后续版本中 {@const} 被视为旧语法。

{const}:声明常量

{const} 声明一个不可重新赋值的常量,和 JavaScript 的 const 语义一致:

{#each products as product}
	{const subtotal = product.price * product.quantity}
	{const tax = subtotal * 0.1}
	{const total = subtotal + tax}

	<tr>
		<td>{product.name}</td>
		<td>{subtotal.toFixed(2)}</td>
		<td>{tax.toFixed(2)}</td>
		<td>{total.toFixed(2)}</td>
	</tr>
{/each}

相当于在模板里做中间计算,不必把这些逻辑搬到 <script> 里。

{let}:声明可变变量

{let} 声明一个可重新赋值的变量,和 JavaScript 的 let 一致:

{#each counters as counter}
	{let value = counter.initial}

	<button onclick={() => value++}>+</button>
	<span>{value}</span>
	<button onclick={() => value--}>-</button>
{/each}

每个 {#each} 迭代都有自己的 value 变量,互不干扰。

响应式声明标签

声明标签的真正威力在于配合 Runes 使用。你可以在模板里声明 $state$derived

<script>
	let user = $state({ name: 'Svelte' });
	let editing = $state(false);
</script>

<p>Hello {user.name}</p>
<button onclick={() => editing = true}>编辑名字</button>

{#if editing}
	<!-- 在模板中声明响应式状态 -->
	{let name = $state(user.name)}
	<!-- 在模板中声明派生值 -->
	{const greeting = $derived(`Hello ${name}`)}

	<hr>
	<input bind:value={name} />
	<p>{greeting}</p>

	<button onclick={() => {
		user.name = name;
		editing = false;
	}}>保存</button>
{/if}

这个例子展示了声明标签的典型用法:

  1. editing 为 true 时,进入编辑模式
  2. {let name = $state(user.name)} 创建一个本地响应式副本
  3. {const greeting = $derived(...)} 创建一个基于 name 的派生值
  4. 用户在输入框中修改 namegreeting 实时更新
  5. 点击保存,把 name 写回 user.name,退出编辑
Tip

这种模式很实用——创建一个临时编辑状态,确认后再写回原始数据。用声明标签,编辑状态的作用域被限制在 {#if} 块内,退出编辑后自动清理。

作用域规则

声明标签遵循 JavaScript 的词法作用域规则。声明的变量对同级的后续内容和子级可见:

{const hello = 'hello'}
{hello}  <!-- 'hello' -->

<div>
	{const hello = 'hi'}
	{hello}  <!-- 'hi' -->

	<div>
		{hello}  <!-- 'hi'(继承父级) -->
	</div>
</div>

{hello}  <!-- 'hello'(外层的值) -->

内层声明的变量会遮蔽外层同名变量,和 JavaScript 的块作用域行为一致。

可以引用外部变量

<script>
	let multiplier = 3;
</script>

{#each numbers as n}
	<!-- 引用了外部的 multiplier -->
	{const result = n * multiplier}
	<p>{n} × {multiplier} = {result}</p>
{/each}

与旧语法对比

特性{@const}(旧){const} / {let}(新)
语法{@const x = y}{const x = y} / {let x = y}
可变性只能声明常量const 和 let 都支持
响应式不支持 $state/$derived支持
使用位置只能在块内模板任意位置
版本所有 Svelte 55.56+

迁移指南

<!-- 旧语法 -->
{#each items as item}
	{@const total = item.price * item.qty}
	<p>{total}</p>
{/each}

<!-- 新语法 -->
{#each items as item}
	{const total = item.price * item.qty}
	<p>{total}</p>
{/each}

去掉 @ 符号即可。功能完全等价,但新语法还额外支持 let$state$derived

Note

目前两种语法都能使用。官方推荐新代码用声明标签({const}/{let}),旧代码可以逐步迁移。{@const} 在未来版本可能被移除。

实用模式

模式一:条件计算

{#if items.length > 0}
	{const max = Math.max(...items.map(i => i.value))}
	{const min = Math.min(...items.map(i => i.value))}
	{const avg = items.reduce((s, i) => s + i.value, 0) / items.length}

	<p>最大值:{max},最小值:{min},平均值:{avg.toFixed(1)}</p>
{/if}

模式二:本地状态隔离

{#each tabs as tab}
	{let open = $state(false)}

	<div class="tab">
		<button onclick={() => open = !open}>
			{tab.title} {open ? '▼' : '▶'}
		</button>
		{#if open}
			<div class="content">{tab.content}</div>
		{/if}
	</div>
{/each}

每个标签页有自己的 open 状态,互不影响。

本节回顾

  • 声明标签是 Svelte 5.56+ 新特性,在模板中用 {const}{let} 声明变量
  • {const} 声明常量,{let} 声明可变变量
  • 支持配合 $state$derived 在模板中声明响应式状态和派生值
  • 遵循词法作用域规则,内层可遮蔽外层同名变量
  • 相比旧语法 {@const},声明标签更灵活(支持 let、$state、$derived,使用位置不限)
  • {@const} 被视为旧语法,推荐用 {const} 替代
  • 声明标签只有 {const}{let} 两种,其他模板语法({#if}{#each} 等)保持不变