bind:
数据通常是从父级流向子级。bind:
指令允许数据反向流动,从子级流向父级。
一般语法是 bind:property={expression}
,其中 expression
是一个 lvalue(即一个变量或一个对象属性)。当表达式的标识符与属性同名时,我们可以省略表达式——换句话说,这两者是等价的:
<input bind:value={value} />
<input bind:value />
Svelte 创建了一个事件监听器来更新绑定值。如果元素已经有一个相同事件的监听器,那个监听器会在绑定值更新之前触发。
大多数绑定是 双向的,这意味着对值的更改会影响元素,反之亦然。有一些绑定是 只读的,这意味着更改它们的值不会对元素产生影响。
函数绑定
您还可以使用 bind:property={get, set}
,其中 get
和 set
是函数,允许您进行验证和转换:
<input bind:value={
() => value,
(v) => value = v.toLowerCase()}
/>
对于只读绑定如尺寸绑定,get
值应为 null
:
<div
bind:clientWidth={null, redraw}
bind:clientHeight={null, redraw}
>...</div>
函数绑定在 Svelte 5.9.0 及更新版本中可用。
<input bind:value>
在 <input>
元素上使用 bind:value
指令绑定输入的 value
属性:
<script>
let message = $state('hello');
</script>
<input bind:value={message} />
<p>{message}</p>
对于数字输入(type="number"
或 type="range"
),该值将被强制转换为数字(demo):
<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>
如果输入为空或无效(在 type="number"
的情况下),值为 undefined
。
自 5.6.0 版本开始,如果 <input>
有 defaultValue
并且是表单的一部分,当表单被重置时,它将恢复为该值,而不是空字符串。请注意,对于初始渲染,除非绑定值为 null
或 undefined
,否则绑定值优先。
<script>
let value = $state('');
</script>
<form>
<input bind:value defaultValue="not the empty string">
<input type="reset" value="Reset">
</form>
请谨慎使用重置按钮,并确保用户在提交表单时不会意外点击它们。
<input bind:checked>
复选框和单选输入可以绑定 bind:checked
:
<label>
<input type="checkbox" bind:checked={accepted} />
接受条款和条件
</label>
自 5.6.0 版本开始,如果 <input>
有 defaultChecked
属性并且是表单的一部分,当表单被重置时,它将恢复为该值,而不是 false
。请注意,对于初始渲染,除非绑定值为 null
或 undefined
,否则绑定值优先。
<script>
let checked = $state(true);
</script>
<form>
<input type="checkbox" bind:checked defaultChecked={true}>
<input type="reset" value="Reset">
</form>
<input bind:group>
一起工作的 input 元素,比如单选框、复选框,可以使用 bind:group
。
<script>
let tortilla = $state('Plain');
/** @type {Array<string>} */
let fillings = $state([]);
</script>
<!-- 分组的单选输入是互斥的 -->
<input type="radio" bind:group={tortilla} value="Plain" />
<input type="radio" bind:group={tortilla} value="Whole wheat" />
<input type="radio" bind:group={tortilla} value="Spinach" />
<!-- 分组的复选框输入填充一个数组 -->
<input type="checkbox" bind:group={fillings} value="Rice" />
<input type="checkbox" bind:group={fillings} value="Beans" />
<input type="checkbox" bind:group={fillings} value="Cheese" />
<input type="checkbox" bind:group={fillings} value="Guac (extra)" />
bind:group
仅在 input 位于同一 Svelte 组件中时才有效。
<input bind:files>
在 <input>
元素上使用 type="file"
时,您可以使用 bind:files
获取所选文件的 FileList
。当您想以编程方式更新文件时,您始终需要使用 FileList
对象。目前无法直接构造 FileList
对象,因此您需要创建一个新的 DataTransfer
对象,并从中获取 files
。
<script>
let files = $state();
function clear() {
files = new DataTransfer().files; // null 或 undefined 无效
}
</script>
<label for="avatar">上传图片:</label>
<input accept="image/png, image/jpeg" bind:files id="avatar" name="avatar" type="file" />
<button onclick={clear}>清空</button>
FileList
对象也不能被修改,因此如果您想从列表中删除单个文件,则需要创建一个新的 DataTransfer
对象,并添加您想保留的文件。
DataTransfer
在服务器端 JavaScript 运行时可能不可用。将绑定到files
的状态保持未初始化可以防止组件在服务端渲染时出现潜在错误。
<select bind:value>
<select>
值绑定对应于所选 <option>
的 value
属性,可以是任何值(不仅仅是 DOM 中通常使用的字符串)。
<select bind:value={selected}>
<option value={a}>a</option>
<option value={b}>b</option>
<option value={c}>c</option>
</select>
<select multiple>
元素的行为类似于复选框组。绑定的变量是一个数组,其中包含与每个选定的 <option>
的 value
属性对应的条目。
<select multiple bind:value={fillings}>
<option value="Rice">米饭</option>
<option value="Beans">豆子</option>
<option value="Cheese">奶酪</option>
<option value="Guac (extra)">鳄梨(额外)</option>
</select>
当 <option>
的值与其文本内容匹配时,可以省略该属性。
<select multiple bind:value={fillings}>
<option>米饭</option>
<option>豆子</option>
<option>奶酪</option>
<option>鳄梨(额外)</option>
</select>
您可以通过给 <option>
添加一个 selected
属性(如果是 <select multiple>
,那可以设置多个 selected
属性),为 <select>
设置默认值。
如果 <select>
是表单的一部分,在表单重置时将恢复到该选择。请注意,对于初始渲染,如果绑定的值不是 undefined
,则绑定的值优先。
<select bind:value={selected}>
<option value={a}>a</option>
<option value={b} selected>b</option>
<option value={c}>c</option>
</select>
<audio>
<audio>
元素有自己的一组绑定——五个双向绑定...
...以及七个只读绑定:
<audio src={clip} bind:duration bind:currentTime bind:paused></audio>
<video>
<video>
元素具有与 (audio)[#audio] 元素相同的所有绑定,外加只读的 videoWidth
和 videoHeight
绑定。
<img>
<img>
元素有两个只读绑定:
<details bind:open>
<details>
元素绑定到 open
属性。
<details bind:open={isOpen}>
<summary>How do you comfort a JavaScript bug?</summary>
<p>You console it.</p>
</details>
可编辑内容绑定
具有 contenteditable
属性的元素支持以下绑定:
innerText
和textContent
之间有微妙的差异。
<div contenteditable="true" bind:innerHTML={html} />
尺寸
所有可见元素都有以下只读绑定,通过 ResizeObserver
测量:
<div bind:offsetWidth={width} bind:offsetHeight={height}>
<Chart {width} {height} />
</div>
display: inline
元素没有宽度或高度(除了具有“固有”尺寸的元素,如<img>
和<canvas>
),并且无法通过ResizeObserver
进行观察。您需要将这些元素的display
样式更改为其他值,例如inline-block
。
bind:this
bind:this={dom_node}
要获取对 DOM 节点的引用,请使用 bind:this
。该值在组件挂载之前是 undefined
—— 换句话说,您应该在 effect 或事件处理程序内部读取它,而不是在组件初始化期间读取:
<script>
/** @type {HTMLCanvasElement} */
let canvas;
$effect(() => {
const ctx = canvas.getContext('2d');
drawStuff(ctx);
});
</script>
<canvas bind:this={canvas} />
组件也支持 bind:this
,允许您以编程方式与组件实例进行交互。
<ShoppingCart bind:this={cart} />
<button onclick={() => cart.empty()}> 清空购物车 </button>
<script>
// 所有实例导出都可在实例对象上使用
export function empty() {
// ...
}
</script>
<script lang="ts">
// 所有实例导出都可在实例对象上使用
export function empty() {
// ...
}
</script>
bind:property for components
bind:property={variable}
您可以使用与元素相同的语法绑定组件属性。
<Keypad bind:value={pin} />
虽然 Svelte 的 props 在不绑定的情况下是响应式的,但默认情况下这种响应性只能向下流入组件。使用 bind:property
可以让组件内部对属性的更改向上传递出组件。
要将属性标记为可绑定的,请使用 $bindable
符文:
<script>
let { readonlyProperty, bindableProperty = $bindable() } = $props();
</script>
将属性声明为可绑定意味着它 可以 使用 bind:
,但不是说它 必须 使用 bind:
。
可绑定属性可以有一个后备值:
<script>
let { bindableProperty = $bindable('fallback value') } = $props();
</script>
此后备值 仅 在属性 未 被绑定时适用。当属性被绑定并且存在后备值时,父级必须提供一个不同于 undefined
的值,否则会抛出运行时错误。这可以防止出现难以推理的情况,即不清楚应该应用哪个值。