🐾

Svelte5のイベント修飾子の代替手段

2024/07/18に公開


Svelte5ではイベント修飾子(Event modifiers)が廃止されたのでそれぞれの代替ラップ関数を作成しました。ほぼ参考文献そのままではありますが、一応TypeScriptということと自分用備忘メモとして意味があるということにしておきます。

イベント修飾子一覧

修飾子 動作
preventDefault event.preventDefault()を最初に実行
stopPropagation event.stopPropagation()を実行
once ハンドラを最初に実行した後に削除
self 要素がevent.targetの場合のみトリガ
trusted event.isTrustedtrueの場合のみトリガ
capture addEventListener時に{capture: true}指定
passive addEventListener時に{passive: true}指定
nonpassive addEventListener時に{passive: false}指定

代替ラップ関数

preventDefault

function prevent<T extends Element>(fn?: (this: T, evt: Event) => void) {
  return function(this: T, evt: Event) {
    if (fn !== undefined) {
      evt.preventDefault();
      fn.call(this, evt);
    }
  };
}

stopPropagation

function stop<T extends Element>(fn?: (this: T, evt: Event) => void) {
  return function(this: T, evt: Event) {
    if (fn !== undefined) {
      evt.stopPropagation();
      fn.call(this, evt);
    }
  };
}

once

function once<T extends Element>(fn?: (this: T, evt: Event) => void) {
  return function(this: T, evt: Event) {
    if (fn !== undefined) {
      fn.call(this, evt);
    }
    fn = undefined;
  };
}

self

function self<T extends Element>(fn?: (this: T, evt: Event) => void) {
  return function(this: T, evt: Event) {
    if (fn !== undefined && evt.target === this) {
      fn.call(this, evt);
    }
  };
}

trusted

function trusted<T extends Element>(fn?: (this: T, evt: Event) => void) {
  return function(this: T, evt: Event) {
    if (fn !== undefined && evt.isTrusted) {
      fn.call(this, evt);
    }
  };
}

capture

addEventListenerは基本Svelte側で管理されているためラップ関数では対応できない。代替手段としてSvelte5からはイベント名末尾にcaptureを追加した特殊属性を使用することができる。

<button onclickcapture={...}>...</button>

passive & nonpassive

addEventListenerは基本Svelte側で管理されているためラップ関数では対応できず、簡易的な代替手段もない。ユースケースはほぼないだろうという公式の以下見解のため。

Changing the passive option of an event handler, meanwhile, is not something to be done lightly. If you have a use case for it — and you probably don't!

MDNによると主要ブラウザではtouchstart,touchmove,wheel,mousewheelイベントでデフォルトpassive: trueになっているらしい。Safariではwheel,mousewheelでデフォルトpassive: trueになっていないらしいが、wheelについてはpassive: trueになっているという情報もある。このような状況のためほぼ不要という見解に至ったと思われる。どうしても必要な場合は自身でイベント登録する等の制御が必要になる。

参考文献

Discussion