声明标签(Declaration Tags)
本教程共 50 篇 · 第 17 篇 · 更新于 2026-08-05 · 约 6 分钟阅读
本节目标:掌握 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}
这个例子展示了声明标签的典型用法:
editing为 true 时,进入编辑模式- 用
{let name = $state(user.name)}创建一个本地响应式副本 - 用
{const greeting = $derived(...)}创建一个基于name的派生值 - 用户在输入框中修改
name,greeting实时更新 - 点击保存,把
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 5 | 5.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}等)保持不变