Event Delegation
Event Delegation ist ein Muster für eine Vorgehensweise, die einem »Abgesandten« den eventListener zuschiebt, so dass eine ganze Reihe von Elementen auf gleiche Art behandelt werden kann.
Event Delegation macht sich das Event Bubbling zunutze: Events steigen von einem Element in der Bubbling-Phase über alle übergeordneten Elemente bis zum root-Element auf.
Bei einer langen Liste von Elementen, die bei einem Event in ähnlicher Weise behandelt werden, muss nicht jedes Event in einem eigenen Skript behandelt werden. Statt dessen beobachtet der eventListener ein im DOM-Baum übergeordnetes Element, das alle Elemente der Liste enthält.
<div class="gallery">
<div class="flower">
<img src="flowers-01.webp" width="480" height="300" alt="…">
<div class="del">✕</div>
</div>
<div class="flower">
<img src="flowers-02.webp" width="480" height="300" alt="…">
<div class="del">✕</div>
</div>
…
</div>
const gallery = document.querySelector (".gallery");
gallery.addEventListener ("click", (evt) => {
if (evt.target.className === "del") {
evt.target.closest (".flower").remove ();
}
});
Bei einem Klick auf das gallery-Element prüft evt.target.className, ob ein Element mit der CSS-Klasse del vorliegt. Wenn das der Fall ist, greift evt.target.parentElement bzw. evt.target.closest auf das umfassende Element zu, also auf das div-Element mit der CSS-Klasse flower. remove () löscht das Element.
Mehrere Events für ein Element
Um mehrere Event-Typen für ein Element zu registrieren, braucht das Skript eine Schleife oder eine Funktion.
.container { position: relative; overflow: hidden; } #zoomable-image { height: 100%; transition: transform 0.8s ease; } #zoomable-image.zoomed { transform: scale(2); }
const image = document.getElementById("zoomable-image"); const events = ["click", "touchstart"]; function addEventListeners(element, events, handler) { events.forEach(event => { element.addEventListener(event, handler); }); } function toggleZoom() { this.classList.toggle("zoomed"); } addEventListeners(image, events, toggleZoom);
Das Array events enthält die Events, die du registrieren möchtest, in diesem Fall click und touchstart.
const image = document.getElementById("zoomable-image"); const events = ["click", "touchstart"]; function addEventListeners(element, events, handler) { events.forEach(event => { element.addEventListener(event, handler); }); } addEventListeners(image, events, function (evt) { evt.preventDefault(); this.classList.toggle("zoomed"); });
Am Rande: evt.preventDefault() wird hier eingesetzt, damit das Bild auf dem Touchscreen nicht Fullscreen anzeigt.
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 Ziel – zum Event Target – vordringt.
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 …?