Signatur
Beschreibung
EventTarget ist das grundlegende Interface des DOM-Ereignismodells. Alle Objekte, die Ereignisse empfangen können, implementieren es, zum Beispiel Element, Document, Window, XMLHttpRequest, WebSocket, AbortSignal, Worker oder MediaQueryList. Es stellt genau drei Methoden bereit: addEventListener(), removeEventListener() und dispatchEvent().
Seit einigen Jahren lässt sich EventTarget auch direkt über new EventTarget() erzeugen oder per class MyEmitter extends EventTarget erweitern. Damit bekommt man einen leichtgewichtigen, standardkonformen Event-Emitter, ohne eine Bibliothek einzubinden oder DOM-Knoten zu missbrauchen. Das eignet sich für Stores, Service-Klassen oder die Kommunikation zwischen Modulen.
Listener lassen sich über ein Optionsobjekt feiner steuern: once entfernt den Listener nach dem ersten Aufruf automatisch, passive sichert dem Browser zu, dass preventDefault() nicht aufgerufen wird (das verbessert die Scroll-Leistung), capture registriert den Listener für die Capture-Phase, und mit signal kann man Listener über einen AbortController gesammelt entfernen.
Eigene Ereignisse erzeugt man mit new Event() oder new CustomEvent(), wobei CustomEvent Nutzdaten in detail mitgibt. dispatchEvent() ruft die Listener synchron auf und gibt false zurück, wenn ein abbrechbares Event per preventDefault() abgebrochen wurde.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Ereignistyp für addEventListener/removeEventListener, z. B. "click". Groß- und Kleinschreibung wird unterschieden. |
|
| $listener Pflicht | Function | { handleEvent(event) } | null | Callback-Funktion oder Objekt mit einer Methode handleEvent(), das beim Ereignis aufgerufen wird. |
|
| $options | boolean | { capture?: boolean, once?: boolean, passive?: boolean, signal?: AbortSignal } | false | Ein boolescher Wert entspricht capture. Das Objekt steuert Capture-Phase, einmalige Ausführung, passives Verhalten und das Entfernen per AbortSignal. |
| $event Pflicht | Event | Das Event-Objekt, das an dispatchEvent() übergeben und an alle passenden Listener ausgeliefert wird. |
Rückgabewert
new EventTarget() liefert eine neue Instanz. addEventListener() und removeEventListener() geben undefined zurück. dispatchEvent() gibt einen boolean zurück: false, wenn das Event abbrechbar war und preventDefault() aufgerufen wurde, sonst true.Beispiele
Eigenständiges EventTarget erzeugen und nutzen
const bus = new EventTarget();
bus.addEventListener('user:login', (e) => {
console.log(`Willkommen, ${e.detail.name}!`);
});
bus.dispatchEvent(new CustomEvent('user:login', { detail: { name: 'Anna' } }));
Eigene Klasse als Event-Emitter (Warenkorb)
class Warenkorb extends EventTarget {
#artikel = [];
hinzufuegen(artikel) {
this.#artikel.push(artikel);
this.dispatchEvent(new CustomEvent('change', {
detail: { anzahl: this.#artikel.length }
}));
}
}
const korb = new Warenkorb();
korb.addEventListener('change', (e) => {
console.log('Artikel im Korb:', e.detail.anzahl);
});
korb.hinzufuegen({ id: 1, name: 'Buch' });
korb.hinzufuegen({ id: 2, name: 'Stift' });
Mehrere Listener per AbortController entfernen
const controller = new AbortController();
const { signal } = controller;
window.addEventListener('resize', () => console.log('resize'), { signal });
window.addEventListener('scroll', () => console.log('scroll'), { signal, passive: true });
document.addEventListener('keydown', (e) => console.log(e.key), { signal });
// Später, z. B. beim Abbau einer Komponente:
controller.abort(); // entfernt alle drei Listener auf einmal
Abbrechbares Event und Rückgabewert von dispatchEvent
const formular = new EventTarget();
formular.addEventListener('beforesave', (e) => {
if (!e.detail.email.includes('@')) {
e.preventDefault(); // Speichern verhindern
}
});
const speichern = (daten) => {
const ok = formular.dispatchEvent(
new CustomEvent('beforesave', { detail: daten, cancelable: true })
);
console.log(ok ? 'Gespeichert' : 'Abgebrochen');
};
speichern({ email: 'test@example.com' });
speichern({ email: 'ungueltig' });
// Wichtig · Fallstricke
- Gleiche Funktionsreferenz:
removeEventListener()entfernt nur, wenntype, dieselbe Funktionsreferenz und derselbecapture-Wert übergeben werden. Anonyme Pfeilfunktionen lassen sich so nicht entfernen. In dem Fall hilft{ signal }oder{ once: true }. - Doppelte Registrierung: Wird derselbe Listener mit identischem
typeundcapturemehrfach registriert, wird er nur einmal aufgerufen. - Synchron:
dispatchEvent()ruft alle Listener sofort und synchron auf, noch bevor die Methode zurückkehrt. Eine Ausnahme in einem Listener bricht die übrigen Listener nicht ab, sie wird aber gemeldet (reportError). - Kein Bubbling ohne Baum: Ein alleinstehendes
EventTargethat keine Eltern.bubblesundcapturehaben dort keine Wirkung. - Event wiederverwenden: Ein Event-Objekt kann während der laufenden Auslieferung nicht erneut ausgelöst werden (
InvalidStateError). thisin Listenern: Bei normalen Funktionen verweistthisaufcurrentTarget, bei Pfeilfunktionen nicht.- Passive Listener: Chrome und Firefox setzen
passivefürtouchstart,touchmoveundwheelaufwindow,documentundbodystandardmäßig auftrue. Ein Aufruf vonpreventDefault()wird dort ignoriert. - Kompatibilität: Die Methoden werden überall unterstützt. Den Konstruktor bzw.
extends EventTargetgibt es erst seit Chrome 64, Firefox 59, Safari 14 und Node.js 15. Die Optionsignalgibt es ab Chrome 90, Firefox 86, Safari 15. Im alten Internet Explorer (unter 9) gab es stattdessenattachEvent.