bind
データは通常、親から子へと下向きに流れます。bind:
ディレクティブを使用すると、データが子から親へと逆方向に流れるようになります。
一般的な構文は bind:property={expression}
で、expression
は *lvalue* (変数またはオブジェクトのプロパティ) です。式がプロパティと同じ名前の識別子である場合、式を省略できます。つまり、これらは同等です。
<input bind:value={value} />
<input bind:value />
Svelte は、バインドされた値を更新するイベントリスナーを作成します。要素が同じイベントのリスナーを既に持っている場合、そのリスナーがバインドされた値が更新される前に発生します。
ほとんどのバインディングは *双方向* であり、値の変更が要素に影響し、その逆も同様です。いくつかのバインディングは *読み取り専用* であり、値を変更しても要素に影響はありません。
<input bind:value>
<input>
要素の bind:value
ディレクティブは、入力の value
プロパティをバインドします
<script>
let message = $state('hello');
</script>
<input bind:value={message} />
<p>{message}</p>
数値入力 (type="number"
または type="range"
) の場合、値は数値に強制変換されます(デモ)
<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} />
Accept terms and conditions
</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>
連携して動作する入力は、bind:group
を使用できます。
<script>
let tortilla = $state('Plain');
/** @type {Array<string>} */
let fillings = $state([]);
</script>
<!-- grouped radio inputs are mutually exclusive -->
<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" />
<!-- grouped checkbox inputs populate an array -->
<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
は、入力が同じ Svelte コンポーネント内にある場合にのみ機能します。
<input bind:files>
type="file"
の <input>
要素では、bind:files
を使用して、選択したファイルの FileList
を取得できます。プログラムでファイルを更新する場合は、常に FileList
オブジェクトを使用する必要があります。現在、FileList
オブジェクトを直接作成することはできないため、新しい DataTransfer
オブジェクトを作成し、そこから files
を取得する必要があります。
<script>
let files = $state();
function clear() {
files = new DataTransfer().files; // null or undefined does not work
}
</script>
<label for="avatar">Upload a picture:</label>
<input accept="image/png, image/jpeg" bind:files id="avatar" name="avatar" type="file" />
<button onclick={clear}>clear</button>
FileList
オブジェクトも変更できないため、たとえばリストから単一のファイルを削除する場合は、新しい DataTransfer
オブジェクトを作成し、保持したいファイルを追加する必要があります。
DataTransfer
は、サーバー側の JS ランタイムでは利用できない場合があります。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">Rice</option>
<option value="Beans">Beans</option>
<option value="Cheese">Cheese</option>
<option value="Guac (extra)">Guac (extra)</option>
</select>
<option>
の値がテキストコンテンツと一致する場合、属性は省略できます。
<select multiple bind:value={fillings}>
<option>Rice</option>
<option>Beans</option>
<option>Cheese</option>
<option>Guac (extra)</option>
</select>
<select>
にデフォルト値を指定するには、最初に選択する必要がある <option>
(または <select multiple>
の場合は複数のオプション) に selected
属性を追加します。<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>
要素には、独自のバインディングセットがあります。5 つの双方向バインディング...
...および 7 つの読み取り専用バインディング
<audio src={clip} bind:duration bind:currentTime bind:paused></audio>
<video>
<video>
要素には、[#audio] 要素と同じすべてのバインディングに加えて、読み取り専用の videoWidth
および videoHeight
バインディングがあります。
<img>
<img>
要素には、2 つの読み取り専用バインディングがあります
<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 のバインディング
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
になります。つまり、コンポーネントの初期化中ではなく、エフェクトまたはイベントハンドラー内で読み取る必要があります
<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()}> Empty shopping cart </button>
<script>
// All instance exports are available on the instance object
export function empty() {
// ...
}
</script>
コンポーネントに対する bind:property
bind:property={variable}
要素と同じ構文を使用して、コンポーネントのプロパティにバインドできます。
<Keypad bind:value={pin} />
Svelte プロパティはバインディングなしでリアクティブですが、そのリアクティブ性はデフォルトではコンポーネントに下向きにのみ流れます。bind:property
を使用すると、コンポーネント内からのプロパティの変更がコンポーネントの外に流れるようになります。
プロパティをバインド可能としてマークするには、$bindable
ルーンを使用します
<script>
let { readonlyProperty, bindableProperty = $bindable() } = $props();
</script>
プロパティをバインド可能として宣言するということは、bind:
を使用して使用できるということですが、bind:
を使用する必要があるという意味ではありません。
バインド可能なプロパティには、フォールバック値を設定できます
<script>
let { bindableProperty = $bindable('fallback value') } = $props();
</script>
このフォールバック値は、プロパティがバインド*されていない*場合にのみ適用されます。プロパティがバインドされ、フォールバック値が存在する場合、親は undefined
以外の値を提供する必要があります。そうしないと、ランタイムエラーがスローされます。これにより、どの値が適用されるべきか不明確な、推論が難しい状況を防ぐことができます。