メインコンテンツにスキップ

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 属性を持つ要素は、次のバインディングをサポートします

innerTexttextContent の間には、微妙な違いがあります。

<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 をサポートしており、コンポーネントインスタンスをプログラムで操作できます。

App
<ShoppingCart bind:this={cart} />

<button onclick={() => cart.empty()}> Empty shopping cart </button>
ShoppingCart
<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 以外の値を提供する必要があります。そうしないと、ランタイムエラーがスローされます。これにより、どの値が適用されるべきか不明確な、推論が難しい状況を防ぐことができます。

GitHubでこのページを編集する

前へ 次へ