JavaScript: Fortgeschrittene Ereignis-Verarbeitung

Nachteile des traditionellen Event-Handlings

Das traditionelle Event-Handling basiert darauf, dass ein Funktionsobjekt in einer Eigenschaft des Elementobjekts gespeichert wird. Wir erinnern uns an das Schema:

element.onevent = handlerfunktion;

Der Vorteil dieses Schemas ist seine Einfachheit. Will man ein Ereignis überwachen, schreibt man bloß die Handler-Funktion in eine entsprechende Element-Eigenschaft. Der größte Nachteile ist jedoch folgender: Es kann nur eine Handler-Funktion zugleich registriert werden. Denn in der Eigenschaft kann nur eine Funktion gespeichert werden. Weist man eine andere Funktion zu, überschreibt man die erste.

In manchen Fällen mag eine Handler-Funktion für ein Element und Ereignistyp ausreichen. Diese kann schließlich weitere Funktionen aufrufen, sodass nicht der gesamte auszuführende Code direkt in dieser einen Funktion stehen muss. Doch wenn verschiedene Scripte zusammenarbeiten, besteht die Gefahr, dass sie beim traditionellen Event-Handling einander in die Quere kommen.

Wenden wir uns den fortgeschrittenen Modellen für Event-Handling zu, die es problemlos erlauben, mehrere Handler-Funktionen zu registrieren.

Event-Handling gemäß dem DOM-Standard

Das bisher beschriebene traditionelle Schema stammt aus den Anfangstagen von JavaScript. Der Browserhersteller und JavaScript-Erfinder Netscape erfand das Schema einst und andere Browser übernahmen es im Zuge ihrer JavaScript-Unterstützung.

Die Entwicklung ging jedoch weiter: Bei der Standardisierung des Event-Handlings verwarf das World-Wide-Web-Konsortium das traditionelle Event-Handling. Der DOM-Standard sieht ein anderes Modell vor: Alle Elementobjekte und weitere zentrale Objekte besitzen die Methode addEventListener (englisch für Ereignis-Überwacher hinzufügen). Will man dem Element einen Event-Handler zuweisen, so ruft man diese Methode auf.

Event-Handler registrieren: addEventListener

Das standardisierte Schema enthält ebenfalls die drei Bestandteile Elementobjekt, Ereignistyp und Handler-Funktion. Es lautet folgendermaßen:

element.addEventListener('event', handlerfunktion, capturing);

Die Methode erwartet also drei Parameter:

  1. Der erste Parameter ist ein String und enthält den Ereignistyp. Beispiele für den ersten Parameter sind 'click', 'mouseover', 'load', 'submit' und so weiter.
  2. Der zweite Parameter ist der Name der Handler-Funktion. Genauer gesagt ein Ausdruck, der ein Funktionsobjekt ergibt.
  3. Der dritte Parameter bestimmt, für welche Event-Phase der Handler registriert werden soll. Es handelt sich um einen Boolean-Parameter, d.h. sie können true oder false notieren.

    false steht für die Bubbling-Phase, true für die weniger wichtige Capturing-Phase. Die genaue Bedeutung des dritten Parameters wird später erklärt werden. Standardmäßig sollten Sie hier false notieren.

Das folgende Beispiel kennen wir bereits vom traditionellen Event-Handling. Dieses Mal nutzen wir die standardisierte Methode addEventListener:

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Beispiel für addEventListener</title>
</head>
<body>

<button id="interaktiv">
  Dies ist ein Button ohne Bedeutung, aber mithilfe von JavaScript können wir ihn
  interaktiv gestalten. Klicken Sie diesen Button einfach mal mit der Maus an!
</button>

<script>

function clickHandler() {
  window.alert('Button wurde geklickt!');
}

document.getElementById('interaktiv').addEventListener('click', clickHandler, false);

</script>
</body>
</html>

Folgendes hat sich geändert: Aus der Zuweisung

document.getElementById('interaktiv').onclick = clickHandler;

ist der Aufruf von addEventListener geworden:

document.getElementById('interaktiv').addEventListener('click', clickHandler, false);

Das obige Beispiel funktioniert in allen modernen Browsern, jedoch nicht im Internet Explorer vor der Version 9. Die unterstützen den DOM-Standard noch nicht und die Methode addEventListener ist ihnen unbekannt.

Der Internet Explorer unterstützt den DOM-Events-Standard erst ab Version 9. Älteren Internet-Explorer-Versionen ist die Methode addEventListener unbekannt. Sie unterstützen stattdessen ein proprietäres Modell.

Der Hauptvorteil von addEventListener ist, dass Sie für ein Element mehrere Handler-Funktionen für denselben Ereignistyp registrieren können. Passen wir das obige Beispiel so an, dass beim button-Element zwei Handler statt einem registriert werden:

function meldung1() {
  window.alert('Erste Handler-Funktion ausgeführt!');
}

function meldung2() {
  window.alert('Zweite Handler-Funktion ausgeführt!');
}

var button = document.getElementById('interaktiv');
button.addEventListener('click', meldung1, false);
button.addEventListener('click', meldung2, false);

Es werden zunächst zwei Handler-Funktionen namens meldung1 und meldung2 definiert.

Um die Wiederholung von document.getElementById('interaktiv') zu vermeiden, suchen wir das Elementobjekt einmal heraus und speichern es in der Variablen button. Dann werden die die Funktionen meldung1 und meldung2 als click-Handler registriert. Wenn Sie auf den Button klicken, dann sollten nacheinander zwei Meldefenster erscheinen – und zwar in der Reihenfolge, in der die Handler mittels addEventListener registriert wurden.

Event-Handler entfernen: removeEventListener

Sie können einmal mit addEventListener registrierte Handler wieder entfernen. Dazu existiert die Schwestermethode removeEventListener (englisch für Ereignis-Empfänger entfernen). Die Methode erwartet dieselben Parameter, die addEventListener beim Registrieren bekommen hat: Einen String mit dem Ereignistyp, die zu löschende Handler-Funktion und schließlich einen Boolean-Wert für die Event-Phase.

Um beide im Beispiel definierten Handler für das button-Element, meldung1 und meldung2, wieder zu entfernen, notieren wir:

button.removeEventListener('click', meldung1, false);
button.removeEventListener('click', meldung2, false);

Event-Handling gemäß Microsoft für ältere Internet Explorer

Bevor der DOM-Standard verabschiedet wurde, erfand Microsoft eine eigene Alternative zum traditionellen Event-Handling. Diese hat sich nicht durchgesetzt und wurde nur vom Internet Explorer umgesetzt. Seit der Version 9 unterstützt der Internet Explorer den DOM-Standard. Daher ist das Microsoft-Modell noch für ältere Internet-Explorer-Versionen interessant.

Das Microsoft-Modell teilt einige Fähigkeiten mit addEventListener und removeEventListener, funktioniert im Detail jedoch anders und bringt einige Eigenheiten mit sich.

Event-Handler registrieren: attachEvent

Das Microsoft-Modell definiert die Methode attachEvent zum Registrieren von Event-Handlern. Elementobjekte sowie einige zentrale Objekte besitzen diese Methode. Das Schema lautet folgendermaßen:

element.attachEvent('onevent', handlerfunktion);

Die Methode erwartet zwei Parameter:

  1. Der erste Parameter ist ein String und enthält den Ereignistyp mit der Vorsilbe on. Beispiele für den ersten Parameter sind 'onclick', 'onmouseover', 'onload', 'onsubmit' und so weiter.
  2. Der zweite Parameter ist der Name der Handler-Funktion. Genauer gesagt ein Ausdruck, der ein Funktionsobjekt ergibt).

Wir greifen das bekannte Beispiel auf und setzen es mit dem Microsoft-Modell um:

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Beispiel für attachEvent</title>
</head>
<body>

<button id="interaktiv">
  Dies ist ein Button ohne Bedeutung, aber mithilfe von JavaScript können wir ihn
  interaktiv gestalten. Klicken Sie diesen Button einfach mal mit der Maus an!
</button>

<script>

function clickHandler() {
  window.alert('Button wurde geklickt!');
}

document.getElementById('interaktiv').attachEvent('onclick', clickHandler);

</script>
</body>
</html>

Das Beispiel hat sich gegenüber dem DOM-Standardmodell nur geringfügig geändert. Anstelle von document.getElementById('interaktiv').addEventListener(…) wurde document.getElementById('interaktiv').attachEvent(…) notiert.

Der Ereignistyp im ersten Parameter enthält nun den Präfix on: Aus 'click' wird 'onclick'. Der dritte Parameter, der die Event-Phase angibt, fällt weg. Denn Microsofts Modell unterstützt nur das Registrieren in der Bubbling-Phase.

Auch mit attachEvent können Sie verschiedene Handler für denselben Ereignistyp definieren. Das obige Beispiel wird entsprechend angepasst:

function meldung1() {
  window.alert('Erste Handler-Funktion ausgeführt!');
}

function meldung2() {
  window.alert('Zweite Handler-Funktion ausgeführt!');
}

var button = document.getElementById('interaktiv');
button.addEventListener('onclick', meldung1);
button.addEventListener('onclick', meldung2);

Das Beispiel enthält nichts neues, die Aufrufe von addEventListener wurden auf die besagte Weise durch attachEvent ausgetauscht.

Event-Handler entfernen: detachEvent

Auch das Microsoft-Modell bietet eine Methode, um registrierte Handler wieder zu entfernen. Sie nennt sich detachEvent und erwartet dieselben Parameter wie sein Gegenstück attachEvent.

Um die besagten click-Handler meldung1 und meldung2 wieder zu entfernen, notieren wir:

button.detachEvent('onclick', meldung1);
button.detachEvent('onclick', meldung2);

Eigenheiten des Microsoft-Modell

Das Microsoft-Modell bringt eine erfreuliche und eine unerfreuliche Besonderheit mit sich:

Browserübergreifendes Event-Handling

Wir haben drei Modelle und deren Detailunterschiede kennengelernt. Sie werden sich sicher fragen, welches Sie nun in der Praxis ohne Bedenken anwenden können.

Mittlerweile unterstützen alle relevanten Browser den DOM-Standard. Das heißt, Sie können problemlos addEventListener und removeEventListener sowie event.target und event.currentTarget (siehe Arbeiten mit dem Event-Objekt) verwenden.

Der Internet Explorer vor Version 9 unterstützt den DOM-Standard nicht. Diese Versionen sind allerdings nicht mehr stark verbreitet. Falls Sie diese Versionen dennoch unterstützen müssen, so sollten Sie eine Bibliothek verwenden, die das browserübergreifende Registrieren von Event-Handlern ermöglicht. Ein Beispiel ist jQuery 1.x.