Javascript EventListener: capture oder bubble?

Javascript addEventListener Warten auf ein Event

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?

18-12-15 SITEMAP

Events reisen vom Root zum Element

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 Elemente auf dem Weg zum getriggerten Element kein Event Handler an, überhören die Elemente das Event.

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

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.

Nach oben

Wenn der Event Listener jedoch auch auf den Elementen über dem getriggerten Element liegt – so z.B. auf den Elemente dieser verschachtelten HTML-Liste –, ist capture angebracht, um das Ereignis an der korrekten Stelle zu empfangen.

bubble false

					
  • Element 1
  • Element 2
    • Element 3
    • Element 4
  • Element 5
    • Element 6
    • Element 7
      • Element 8
      • Element 9
  • Element 10
bubble true – capture

					
  • Element 1
  • Element 2
    • Element 3
    • Element 4
  • Element 5
    • Element 6
    • Element 7
      • Element 8
      • Element 9
  • Element 10

Bubble: Bei einem Klick auf einen Text der ersten Liste reagiert das Parent-Element,
Capture: Bei einem Klick auf ein Element der zweiten Liste nur das Element selber. Darum zeigt die dunkle Konsole über der Liste bei einem Klick auf Element 9 den Text Element 5, ein Klick auf die bubble:true-Liste den Text Element 9.

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
let b1 = document.querySelector("#b1");
b1.addEventListener ("click", function (){
   b1.classList.toggle ("red");
   }
);

let 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 …?