CSS, HTML und Javascript mit {stil}

Javascript addEventListener • removeEventListener

Javascript addEventListener und removeEventListener

Javascript addEventListener ist eine zentrale Funktion, die Events und die dazugehörigen Aktionen registriert. addEventListener behandelt Events für window, document oder individuelle Elemente der Webseite. removeEventListener löst den Event Handler wieder vom Ereignis.

addEventListener registriert Events wie das Laden der Webseite, den Klick auf ein Element, die Antwort auf einen XMLHttpRequest oder das Laden eines Videos und ruft eine Funktion (die auch als Event Handler bezeichnet wird) auf, sobald das Event feuert.

window.addEventListener ('load', myFunction, false);
var elem = document.getElementById('elem');
elem.addEventListener ('click', myFunction, false);
elem.addEventListener ('touch', myFunction, false);

Mit addEventListener können theoretisch beliebig viele Events für ein Element angemeldet werden.

Event Listener des DOM
elem.addEventListener(eventType,   // EventType (z.B. click, touch 
                                       o. mouseover)
                      handler,     // aufzurufende Funktion
                      useCapture); // Phase der Aktivierung

Der Handler ist im einfachsten Fall eine Javascript-Funktion, in der die Aktionen durchgeführt werden.

<div id="elem"> … </div>

var elem = document.getElementById('elem');
elem.addEventListener ('click', showElem, false);

function showElem() { … }

addEventListener mit Argumenten

Wenn der Event Handler Argumente braucht, muss er als anonyme Funktion in den Aufruf der Funktion addEventListener geschrieben werden.

elem.addEventListener ('click', 
   
    function() { //<-----anonyme Funktion
      showElem(param1, param2)
    }, 
      
    false);

function showElem(p1, p2) { 
    … 
}

attachEvent in IE8

In IE 8 und älter gibt es anstelle des Event Listener eine ähnliche Methode, die ein Element auf ein Event vorbereitet – attachEvent – mit ähnlichen Argumenten.

elem.attachEvent (event,    <-- EventType (z.B. click 
                                  o. mouseover)
                  handler); <-- aufzurufende Funktion

In IE8 und älter muss das Ereigniss mit "on" beginnen. Das dritte Argument useCapture entfällt, da diese IE-Versionen nur Event-Bubbling implementieren.

Ab IE9 unterstützt Internet Explorer den EventListener des W3C.

capture oder bubble?

Wenn sowohl ein Element als auch Vorfahren des Elements für ein Event registriert sind, erreicht das Event zuerst den Vorfahren und wandert dann zu den Nachkommen? Oder wird das Ereignis zuerst an das Element und dann an die Vorfahren gemeldet?

Javascript addEventListener capture vs bubblewindowdocumenthtmlbodysection1buttonssection2oneButtontwoButtonb1b2b3Hier beginnenEventscapturingbubbling
Ein Event beginnt nicht auf dem getriggerten Element
sondern am ROOT
und reist im DOM-Baum nach unten.

Aus der Sicht des DOM reist ein Ereignis in der Capture-Phase vom ROOT des Dokuments zu seinem Ziel und benachrichtigt auf dem Weg nach unten jedes Element. Liegt für die betroffenen Element kein Event Handler an, überhören die Elemente das Event.

Wenn es die Art des Ereignisses erlaubt, steigt das Ereignis in einer Bubbling-Phase durch den Baum zurück nach oben und könnte in der Bubbling-Phase ebenfalls jedes Element auf dem Weg nach oben triggern.

                               capture  -----+
                                             |
button.addEventListener ("click", alertMe, true);
button.addEventListener ("click", alertMe, false);
                                              ^
                                              |
                                bubble   -----+

Der dritte Parameter von addEventListener – useCapture – legt fest, in welcher Phase ein Event einen Event Listener aktiviert.

Capture
true Zuerst die Event Handler von Vorfahren aufrufen, dann erst den Event Handler des Elements
Bubble
false (default) Zuerst den Event Handler des Elements aufrufen, erst dann die Event Handler von Vorfahren
<body>
    <div id="section1">
        <div id="buttons">
            <div id="oneButton">
                <button id="b1">Button 1</button>
            </div>
            <div id="twoButton">
                <button id="b2">Button 2</button>
                <button id="b3">Button 3</button>
            </div>
        </div>
    </div>
    <div id="section2"> … </div>
</body>

Wenn ein Skript Ereignisse auf verschachtelten HTML-/XML-Elementen registriert, die auf dasselbe Ereigniss warten, führt der Browser beim Bubbling die innerste Registrierung zuerst aus und arbeitet sich dann nach oben vor. Beim Capturing behandelt der Browser das Ereignis auf dem Weg »nach unten«.

Wir ziehen heute bubble (false) vor. Für moderne Skripte macht es kaum Sinn, ein Event von mehreren Event Handlern behandeln zu lassen. Wenn wir auf ein Element klicken, erwarten wir eine Aktion. Darum wird jedes Event in einem eigenen Skript behandelt.

Also können wir den dritten Parameter meist fallen lassen – bubble (false) ist der Default-Wert – und der dritte Parameter ist optional.

stopPropagation

Es gibt aber Situationen, in denen die Erkennung eines Events schon in der Capture-Phase eine wichtige Rolle spielt. Auf dem Weg nach unten kann stopPropagation das Event unterbinden, so dass es nicht bis zum Event Target vordringt.

Javascript addEventListener und stopPropagationwindowdocumenthtmlbodysection1buttonssection2oneButtontwoButtonb1b2b3xcapturing
var b1 = document.querySelector("#b1");
b1.addEventListener ("click", function (){
   b1.classList.toggle ("red");
   }
);

var stopit = document.querySelector("#buttons");
stopit.addEventListener("click", function (eve) {
   eve.stopPropagation ();
}, true)

Die Weiterleitung des Events wird unterbunden, das Event kommt niemals bei seinem eigentlichen Event Target an. Zu einer Bubble-Phase kommt es auch nicht mehr. Finito.

Oft werden sowohl bubble als auch capture ausgeschaltet, damit es nicht zu unvorhergesehenen Aktionen kommt. Dafür gibt es das stopPropagation() sowohl für die modernen Browser als auch für IE.

DOM: Event stopPropagation()
Stopt den Ereignis-Fluss. Kann entweder in der Capture- oder in der Bubble-Phase benutzt werden.
IE: stopPropagation()
In IE ist stopPropagation() keine Methode, sondern eine Boole'sche Eigenschaft, die auf true gesetzt wird, damit das Ereignis nicht aufsteigt (bubbling)

Auch wenn wir bubble in den meisten Fällen gern abschalten würden, kann das zu unvorhergesehenen Fehlern führen. Vielleicht hängt ein Plugin vom Event ab …?

removeEventListener Event Handler entbinden

Zu addEventListener / attachEvent gibt es ein Gegenstück removeEventListener bzw detachEvent, das den Event Handler vom Event entbindet:

var elem = document.getElementById('elem');

// Event Handler auf elem ansetzen
elem.addEventListener("click", myFunction);

// Event Handler von elem entfernen
elem.removeEventListener("click", myFunction);

// IE8 und älter
elem.detachEvent("onclick", myFunction);

removeEventListener funktioniert nur bei externen Funktionsaufrufen. Wurde der Event Handler durch eine anonyme Funktion aktiviert, funktioniert removeEventListener nicht.

attachEvent für IE8

Mozilla, Safari und Opera implementieren die Methode addEventListener des W3C seit 2001, seit IE9 unterstützt auch Internet Explorer addEventListener.

Die Konzepte des Event Listeners bzw. attachEvent sind sich ähnlich genug, um die Differenzen unter einer einfachen Funktion zu verstecken. Ein Script prüft, welches der beiden Konzepte vom Browser unterstützt wird – addEventListener vom W3C oder attachEvent in IE.

function myfunc() {
   …
}
if (window.addEventListener) 
    window.addEventListener("load", myfunc);

else if (window.attachEvent) 
   window.attachEvent("onload", myfunc);

else window.onload = myfunc;

Das onload-Problem

An einem generellen Problem ändert auch der eventListener des W3C nichts: Sowohl mit addEventListener als auch mit attachEvent kann der Handler erst ausgeführt werden, wenn das Tag des Elements im Browser geladen wurde.

Die Funktion muss innerhalb einer Funktion aufgerufen werden, die von einem window.onload-Event Handler angestossen wurde, nachdem alle Elemente des Dokuments (das gesamte Markup, Style Sheets, Bilder und Plugins) geladen wurden.

Wird ein Ereignis-Handler registriert, bevor der Browser das HTML-Element geladen hat, kommt es zu einem JavaScript-Fehler: Das Objekt ist unbekannt.

Das Warten auf das Laden des Dokuments (mit sämtlichen Bilder, Plugins ... ) führt zu einer Verzögerung bis zum Skript-Aufruf.

Events mit jQuery

Dem Ärger mit verschiedenen Methoden zur Registrierung von Ereignissen und damit verbundenen Aktionen entgegnet die Javascript-Library jQuery mit einem Cross-Browser-Aufruf:

Skripte starten mit jQuery

$(document).ready(function() {
   // dieser Code wird ausgeführt, wenn das HTML-Dokument
   // geladen – also das DOM fertig aufgebaut – ist.
   $("h1").text("Das DOM ist geladen und kann durchquert werden");
});

$(document).ready(function() wartet nicht einmal, bis das gesamte Dokument im Browser geladen ist, sondern tritt bereits in Aktion, wenn das HTML-Dokument geladen ist und der DOM-Baum durchquert werden kann. Das ist kürzer als die Zeit bis zum vollständigen Laden aller Dokumente einer Webseite.

Dazu muss allerdings die jQuery-Library vor allen anderen Skripten in das Dokument geladen werden.