🍘

Svelte入門(2)(途中。)

2024/10/02に公開

本記事は以下の記事の続きです。
https://zenn.dev/senbei139/articles/3a8adf88daefab

はじめに

チュートリアルは以下の4部構成になっており、今回は1. Basic Svelteのうち、
Events、Bindings、Lifesycle、Storesの項目を対象とします。(1つの記事が長くなりすぎてしまうので。。)

  1. Basic Svelte
  2. Advanced Svelte
  3. Basic SvelteKit
  4. Advanced SvelteKit

https://learn.svelte.jp/tutorial/dom-events

Events

Domのイベント

Svelteではon:click(Svelte入門(1)で出てきたボタン押下時のイベント)のように、
on:{イベント}と書くことで様々なDOMイベントをリスニングすることができます。
https://developer.mozilla.org/ja/docs/Web/API/Element#イベント

Sample.svelte
<script>
  let targetButton = '';

  const items = [
    'button1',
    'button2'
  ]

  function mouseoverHandler(target) {
    targetButton = target;
  }
  function mouseleaveHandler() {
    targetButton = '';
  }
</script>

{#each items as item}
  <button
    on:mouseover={()=>{mouseoverHandler(item)}}
    on:mouseleave={()=>{mouseleaveHandler()}}
  >
    {item}
  </button>
{/each}

<p>mouse over {targetButton}</p>


実行結果
mouseoverとmouseleaveイベントを利用した例です。

イベントハンドラをインラインで記述

イベントハンドラを関数宣言してインラインで記述することもできます。

Sample.svelte
<script>
  let targetButton = '';

  const items = [
    'button1',
    'button2'
  ]
</script>

{#each items as item}
  <button
    on:mouseover={()=>{targetButton = item;}}
    on:mouseleave={()=>{targetButton = '';}}
  >
    {item}
  </button>
{/each}
<p>mouse over {targetButton}</p>

イベントの動作を変更する

Svelteにはイベント修飾子(modifiers)が用意されており、
それらを利用するとイベントハンドラの動作を変更することができます。

例えば、once修飾子を使用すると一度呼ばれたイベントハンドラが削除されます。
よって、初回動作したらそれ以降は動作しないといった挙動が実現できます。

Sample.svelte
<script>
  let count = 0;

  function increment() {
    count += 1;
  }
</script>

<button on:click|once={increment}>Click</button>
<p>{count}</p>


実行結果

イベント修飾子一覧

  • preventDefault — ハンドラを実行する前にevent.preventDefault()を呼び出す。
  • stopPropagation — 次の要素にイベントが伝播しないようにevent.stopPropagation()を呼び出す。
  • passive — タッチ/ホイールイベントでスクロールのパフォーマンスを向上。
  • nonpassive — passive: falseを明示的に設定する。
  • capture — バブリングではなく、キャプチャ時にハンドラを起動する。
  • self — 設定した要素がevent.targetの場合にのみハンドラをトリガする。
  • trusted — event.isTrustedがtrueの場合にのみハンドラをトリガする。

イベント修飾子は|で連結することが可能です。(on:click|once|capture={...}

dispatchイベント

イベントディスパッチャを使えばコンポーネントからイベントを発信することが可能です。
Childコンポーネントで、ボタンクリック時にcustomEventをdispatchするよう記述し、
Parentコンポーネントで、customEventをキャッチしてalertを出すようにしてみます。

Parent.svelte
<script>
  import Child from './Child.svelte';

  function handleCustomEvent(event) {
    alert(event.detail.text);
  }
</script>

<Child on:customEvent={handleCustomEvent} />
Child.svelte
<script>
  import { createEventDispatcher } from 'svelte';

  const dispatch = createEventDispatcher();  // ディスパッチャを作成

  function handler() {
    dispatch('customEvent', {
      text: 'dispatched custom event'
    });
  }
</script>

<button on:click={handler}>
  Click
</button>


実行結果

イベントフォワーディング

コンポーネントのイベントはネストが深い場合にキャッチできないので、中間のコンポーネントがイベントを転送する必要があります。

例えば、下記のようにGrandchildコンポーネントでdispatchしたイベントをParentコンポーネントでキャッチしたい場合、
Grandchild -> Child -> Parent
Childコンポーネントにもイベントを検知して転送する仕組みが必要となります。

幸いSvelteでは転送用のショートハンドを用意してくれており、「中間のコンポーネントがキャッチしたイベントを内容をそのままにdispatchする」といった冗長な処理を書く必要はありません。
ChildコンポーネントがGrandchildコンポーネントを呼び出す際にon:{イベント名}修飾子を書き加えるだけで済みます。

実際にGrandchildコンポーネントを追加して下記のようにcustomEventイベントを伝搬させてみます。

Parent.svelte
<script>
  import Child from './Child.svelte';

  function handleCustomEvent(event) {
    alert(event.detail.text);
  }
</script>

<Child on:customEvent={handleCustomEvent} />
Child.svelte
<script>
  import Grandchild from './Grandchild.svelte';
</script>

<Grandchild on:customEvent />  // ここ
Grandchild.svelte
<script>
  import { createEventDispatcher } from 'svelte';

  const dispatch = createEventDispatcher();

  function handler() {
    dispatch('customEvent', {
      text: 'dispatched custom event from Grandchild'
    });
  }
</script>

<button on:click={handler}>
  Click
</button>


実行結果
Grandchildで定義した「dispatched custom event from Grandchild」がParentで処理することができました。

DOMイベントも同様に記述することが可能です。

Parent.svelte
<script>
  import Child from './Child.svelte';

  function handleClick() {
    alert('clicked');
  }
</script>

<Child on:click={handleClick} />
Child.svelte
<button on:click>
  Click
</button>

Bindings

Lifesycle

Stores

Discussion