Skip to content

EventManager / createDoubleTapDetector

Eine an den Lebenszyklus gebundene Registrierung von Event-Listenern auf Basis von AbortController, dazu ein kleiner Doppeltipp-Erkenner für Touch-Gesten, dem die Zeigerart gleichgültig ist.

Das Problem, das hier gelöst wird, ist das Wieder-Abmelden von Listenern. removeEventListener greift nur, wenn du ihm exakt dieselbe Funktionsreferenz und dieselben Optionen übergibst, mit denen du registriert hast. Verpackst du den Handler beim Anmelden in eine Pfeilfunktion, bekommst du ihn nie wieder los. Komponenten, die immer wieder ein- und ausgehängt werden, verlieren dann pro Runde einen Listener. AbortController macht aus alldem ein einziges abort().

Verwendung

In einer 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(); // meldet alle Listener ab und macht sich für das nächste Einhängen bereit
  }
}

In gewöhnlichem Seitencode

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(); // aufrufen, wenn der Abschnitt abgebaut wird
}

API

on

Meldet einen Listener an, der an diesen Manager gebunden ist. Verkettbar.

Parameter

ParameterBeschreibungTypStandard
targetDas Ziel des EventsEventTargetErforderlich
typeName des EventsstringErforderlich
handlerDie Handler-FunktionEventListenerErforderlich
optionsDie Optionen von addEventListener ohne signalOmit<AddEventListenerOptions,'signal'>-

Rückgabe

ArgumentBeschreibungTyp
thisDer Manager selbst, zum VerkettenEventManager

delegate

Event-Delegation: hängt einen einzigen Listener an parent und ruft handler nur dann, wenn das Event von einem Nachfahren stammt, auf den selector passt. Verkettbar.

Der Handler bekommt das ursprüngliche Event und das getroffene Element.

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

Parameter

ParameterBeschreibungTypStandard
parentDas Element, an dem dieser eine Listener hängtHTMLElementErforderlich
selectorDer Selektor, auf den ein Nachfahre passen mussstringErforderlich
typeName des EventsstringErforderlich
handler(event, matchedElement) => voidFunctionErforderlich
optionsDie Optionen von addEventListener ohne signalOmit<AddEventListenerOptions,'signal'>-

Rückgabe

ArgumentBeschreibungTyp
thisDer Manager selbst, zum VerkettenEventManager

abort

Meldet alle registrierten Listener ab und legt den internen AbortController neu an. Mehrfaches Aufrufen ist unbedenklich; spätere on()- und delegate()-Aufrufe beginnen in einem sauberen Geltungsbereich.

Rückgabe

Kein Rückgabewert (void)

signal

Das zugrunde liegende AbortSignal, falls du es selbst an addEventListener weiterreichen möchtest.

ArgumentBeschreibungTyp
signalDas Abbruchsignal des ManagersAbortSignal

createDoubleTapDetector

Doppeltipp-Erkennung allein aus rohen (x, y, Zeit)-Werten. Die Zeigerart ist ihr gleichgültig, also arbeitet sie gleich, ob du sie aus Pointer-, Touch- oder Mouse-Events fütterst. Gedacht ist sie für Touch-Gesten – doppelt tippen zum Spulen, zum Zoomen, zum Liken –, wo die Logik aus Zeitfenster und Abstandsschwelle an jeder Stelle neu hergeleitet wird und dabei leicht unauffällig danebengeht: nur eine Achse verglichen, oder nach einem Treffer das Zurücksetzen vergessen, sodass drei schnelle Tipper als zwei überlappende Doppeltipps zählen.

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

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

createDoubleTapDetector(options?)

Parameter (DoubleTapDetectorOptions)

OptionBeschreibungTypStandard
windowMsGrößter erlaubter Abstand zwischen den beiden Tippern, in msnumber300
maxDistancePxGrößte erlaubte Entfernung in der Fläche zwischen den beiden Tippern, in pxnumber60

DoubleTapDetector

ElementBeschreibungTyp
checkVermerkt einen Tipp bei (x, y) und meldet, ob er zusammen mit dem unmittelbar davor einen Doppeltipp ergibt. Wird einer erkannt, beginnt die Erfassung von vorn, sodass ein dritter schneller Tipp ein neues Paar eröffnet, statt zum selben Doppeltipp zu zählen(x: number, y: number, now?: number) => boolean
resetVergisst den zuletzt vermerkten Tipp; aufrufen, sobald eine andere Geste als ein Tipp beginnt (etwa ein Ziehen)() => void

Veröffentlicht unter der MIT-Lizenz.