bind: 双向绑定
本教程共 50 篇 · 第 20 篇 · 更新于 2026-08-05 · 约 6 分钟阅读
本节目标:学会使用 bind: 指令实现数据双向绑定,掌握 input、checkbox、radio、select 等表单元素的绑定方式,以及组件 Props 绑定。
数据双向流动
默认情况下,Svelte 里的数据是单向流动的——从父到子。但表单场景有个痛点:用户输入了数据,你得监听 input 事件再更新变量,很啰嗦。
bind: 指令解决了这个问题。它让数据可以双向流动:变量变了,输入框更新;用户输入了,变量也跟着变。
打个比方,单向数据流像是单行道——只能从父到子。bind: 则像双行道——来回两个方向都能走。
<script>
let message = $state('hello');
</script>
<!-- 输入框的值和 message 双向绑定 -->
<input bind:value={message} />
<p>{message}</p>
你试试在输入框里打字,下面的 <p> 会实时更新。不需要写任何事件监听代码。
简写形式
当变量名和属性名相同时,可以省略值部分。
<script>
let value = $state('');
</script>
<!-- 这两种写法完全等价 -->
<input bind:value={value} />
<input bind:value />
数字输入
对于 type="number" 或 type="range" 的输入框,Svelte 会自动把值转成数字类型。
<script>
let a = $state(1);
let b = $state(2);
</script>
<label>
<input type="number" bind:value={a} min="0" max="10" />
<input type="range" bind:value={a} min="0" max="10" />
</label>
<label>
<input type="number" bind:value={b} min="0" max="10" />
<input type="range" bind:value={b} min="0" max="10" />
</label>
<p>{a} + {b} = {a + b}</p>
Note如果数字输入框为空或输入了无效内容,绑定的值会变成
undefined。
bind:checked 复选框
复选框用 bind:checked 绑定布尔值。
<script>
let accepted = $state(false);
</script>
<label>
<input type="checkbox" bind:checked={accepted} />
同意服务条款
</label>
{#if accepted}
<p>感谢同意!可以继续注册。</p>
{:else}
<p>请先同意条款。</p>
{/if}
bind:group 单选与多选
bind:group 是处理一组互相关联的输入框的利器。
单选按钮
单选按钮绑定到一个标量变量,选中的那个 value 会赋给变量。
<script>
let flavor = $state('chocolate');
</script>
<label><input type="radio" bind:group={flavor} value="chocolate" /> 巧克力</label>
<label><input type="radio" bind:group={flavor} value="vanilla" /> 香草</label>
<label><input type="radio" bind:group={flavor} value="strawberry" /> 草莓</label>
<p>你选择了:{flavor}</p>
复选框组
复选框组绑定到一个数组,选中的值会被添加到数组中。
<script>
let toppings = $state([]);
</script>
<label><input type="checkbox" bind:group={toppings} value="珍珠" /> 珍珠</label>
<label><input type="checkbox" bind:group={toppings} value="椰果" /> 椰果</label>
<label><input type="checkbox" bind:group={toppings} value="红豆" /> 红豆</label>
<p>加料:{toppings.join('、') || '什么都不加'}</p>
Note
bind:group只在同一组件内的输入框之间生效。跨组件的分组成员不共享。
select 下拉框
<select> 元素绑定到选中 <option> 的 value 属性。
<script>
let selected = $state('a');
</script>
<select bind:value={selected}>
<option value="a">选项 A</option>
<option value="b">选项 B</option>
<option value="c">选项 C</option>
</select>
<p>选中了:{selected}</p>
多选下拉框 <select multiple> 绑定到一个数组:
<script>
let selected = $state([]);
</script>
<select multiple bind:value={selected}>
<option value="apple">苹果</option>
<option value="banana">香蕉</option>
<option value="orange">橙子</option>
</select>
<p>选中的水果:{selected.join('、') || '未选择'}</p>
Tip当
<option>的 value 和文本内容相同时,可以省略value属性,Svelte 会自动用文本内容作为值。
textarea 多行文本
<textarea> 的绑定方式跟 <input> 一样。
<script>
let content = $state('在这里输入内容...');
</script>
<textarea bind:value={content} rows="5" cols="40"></textarea>
<p>已输入 {content.length} 个字符</p>
元素尺寸绑定
所有可见元素都支持只读的尺寸绑定,Svelte 底层用 ResizeObserver 来监听。
<script>
let w = $state(0);
let h = $state(0);
</script>
<div bind:clientWidth={w} bind:clientHeight={h}>
改变窗口大小看看数值变化
</div>
<p>宽度:{w}px,高度:{h}px</p>
可绑定的尺寸属性包括:
| 属性 | 说明 |
|---|---|
clientWidth | 元素内部宽度(含 padding,不含边框) |
clientHeight | 元素内部高度 |
offsetWidth | 元素整体宽度(含边框) |
offsetHeight | 元素整体高度 |
Note
display: inline的元素没有宽高,不能用尺寸绑定。需要改成inline-block或block。
contenteditable 绑定
带有 contenteditable 属性的元素,可以绑定 innerHTML、innerText、textContent。
<script>
let html = $state('<p>可编辑内容</p>');
</script>
<div
contenteditable="true"
bind:innerHTML={html}
style="border: 1px solid #ccc; padding: 10px;"
></div>
<pre>{html}</pre>
details 展开
<details> 元素支持绑定 open 属性。
<script>
let isOpen = $state(false);
</script>
<details bind:open={isOpen}>
<summary>点击展开/收起</summary>
<p>这里是详细内容。</p>
</details>
<p>当前状态:{isOpen ? '展开' : '收起'}</p>
组件 Props 绑定
bind: 不仅能绑定 DOM 元素,还能绑定组件的 Props。不过子组件需要用 $bindable 声明这个 Prop 是可绑定的。
<!-- FancyInput.svelte -->
<script>
let { value = $bindable() } = $props();
</script>
<input bind:value={value} style="color: deeppink;" />
<!-- App.svelte -->
<script>
import FancyInput from './FancyInput.svelte';
let message = $state('hello');
</script>
<!-- 父组件用 bind: 绑定子组件的 value -->
<FancyInput bind:value={message} />
<p>{message}</p>
Tip
$bindable可以设置兜底值:let { value = $bindable('默认值') } = $props()。兜底值只在父组件没有绑定该 Prop 时生效。
函数绑定
从 Svelte 5.9.0 开始,bind: 支持函数形式的绑定,可以做一些验证和转换。
<script>
let value = $state('');
// 读取时直接返回,写入时转成小写
function getValue() {
return value;
}
function setValue(v) {
value = v.toLowerCase();
}
</script>
<input bind:value={getValue, setValue} />
<p>{value}</p>
本节回顾
bind:value实现文本输入双向绑定,数字输入框会自动转换类型bind:checked绑定复选框的布尔状态bind:group处理单选按钮(绑定标量)和复选框组(绑定数组)<select>绑定选中项的 value,<select multiple>绑定数组- 元素尺寸绑定(
clientWidth等)是只读的,底层用ResizeObserver - 组件 Props 绑定需要子组件用
$bindable声明