Skip to content

EventManager / createDoubleTapDetector

AbortController を土台にした、ライフサイクルに閉じたイベントの登録簿です。あわせて、ポインターの種類を問わない、タッチのジェスチャー向けの小さなダブルタップの検出器も入っています。

これが解くのは、リスナーを 外すほう の問題です。removeEventListener が効くのは、登録したときと まったく同じ 関数の参照とオプションを渡したときだけです。渡す途中でハンドラーをアロー関数で包んでしまえば、もう二度と外せません。マウントとアンマウントを繰り返すコンポーネントは、そのたびにリスナーをひとつずつ漏らしていきます。AbortController は、そのすべてを abort() ひと呼びに変えます。

使い方

Web Component の中で

ts
import { EventManager } from 'ranuts/utils';

class MyElement extends HTMLElement {
  private _events = new EventManager();

  connectedCallback() {
    this._events.on(this._input, 'input', this.handleInput).on(this, 'click', this.handleClick, { capture: true });
  }

  disconnectedCallback() {
    this._events.abort(); // すべてのリスナーを外し、次の接続に備えて仕切り直します
  }
}

ふつうのページのコードで

ts
function initSection(container: HTMLElement) {
  const scope = new EventManager();

  scope.on(input, 'input', handleSearch).delegate(container, '[data-action]', 'click', (ev, target) => {
    handleAction(target.getAttribute('data-action'));
  });

  return () => scope.abort(); // その区画を片づけるときに呼びます
}

API

on

このマネージャーに閉じたリスナーを登録します。つないで書けます。

パラメーター

パラメーター説明既定値
targetイベントの相手EventTarget必須
typeイベントの名前string必須
handlerハンドラーの関数EventListener必須
optionsaddEventListener のオプションから signal を除いたものOmit<AddEventListenerOptions,'signal'>-

戻り値

引数説明
thisこのマネージャー。つないで書くためのものですEventManager

delegate

イベントの委譲です。parentひとつだけ リスナーを付け、selector に当てはまる子孫からイベントが起きたときにかぎり handler を呼びます。つないで書けます。

ハンドラーは、もとのイベントと、当てはまった要素を受け取ります。

ts
scope.delegate(list, '.item', 'click', (ev, item) => {
  console.log(item.getAttribute('data-id'));
});

パラメーター

パラメーター説明既定値
parentただひとつのリスナーを結び付ける要素HTMLElement必須
selector子孫が当てはまるべきセレクターstring必須
typeイベントの名前string必須
handler(event, matchedElement) => voidFunction必須
optionsaddEventListener のオプションから signal を除いたものOmit<AddEventListenerOptions,'signal'>-

戻り値

引数説明
thisこのマネージャー。つないで書くためのものですEventManager

abort

登録したリスナーをすべて外し、内側の AbortController を作り直します。何度呼んでも大丈夫です。そのあとの on()delegate() は、まっさらなところから始まります。

戻り値

戻り値はありません(void

signal

土台の AbortSignal です。自分で addEventListener に渡したいときのために公開しています。

引数説明
signalこのマネージャーの中断シグナルAbortSignal

createDoubleTapDetector

生の (x, y, 時刻) の標本からダブルタップを見分けます。ポインターの種類を問わないので、Pointer、Touch、Mouse のどのイベントから渡しても同じように働きます。タッチのジェスチャー(ダブルタップで頭出し、拡大、いいね)のために作られました。この手の場面では、時刻と距離のしきい値の判定を呼び出しのたびに書き直すと、気づきにくい形で間違えやすいのです。片方の軸しか比べていない、あるいは当たったあとに仕切り直すのを忘れて、素早い 3 回のタップが重なり合ったダブルタップ 2 回として数えられてしまう、といった具合に。

ts
import { createDoubleTapDetector } from 'ranuts/utils';

const detector = createDoubleTapDetector();
el.addEventListener('pointerup', (e) => {
  if (detector.check(e.clientX, e.clientY)) seek();
});

createDoubleTapDetector(options?)

パラメーター(DoubleTapDetectorOptions

オプション説明既定値
windowMs2 回のタップのあいだの、許される最大の間隔(ミリ秒)number300
maxDistancePx2 回のタップのあいだの、平面上で許される最大の距離(px)number60

DoubleTapDetector

メンバー説明
check(x, y) でのタップを記録し、それが直前のタップとダブルタップを成すかどうかを報せます。ダブルタップと見なした時点で追跡を仕切り直すので、素早い 3 回目のタップは同じダブルタップの一部として数えられず、新しい組の始まりになります(x: number, y: number, now?: number) => boolean
reset最後に記録したタップを忘れます。タップ以外のジェスチャー(ドラッグなど)が始まったときに呼んでください() => void

MIT ライセンスのもとで公開されています。