首页 / Svelte 5 入门教程 / bind: 双向绑定

Svelte 5 入门教程

bind: 双向绑定

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

SvelteSvelte 5bind双向绑定表单

本节目标:学会使用 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-blockblock

contenteditable 绑定

带有 contenteditable 属性的元素,可以绑定 innerHTMLinnerTexttextContent

<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 声明