Ein Handler für die ganze Liste
Eine Liste kann viele Einträge haben: zehn, hundert oder neue, die dein Skript später hinzufügt. Jedem Eintrag einen eigenen Handler zu geben, wäre viel Arbeit. Es geht einfacher: ein Handler für die ganze Liste.
Das funktioniert, weil Ereignisse aufsteigen (englisch „bubble up“). Ein Klick auf einen Eintrag ist auch ein Klick auf alles, worin der Eintrag steht: die Liste, den body und die ganze Seite. Der Klick-Handler der Liste läuft also, wenn jemand auf irgendeinen ihrer Einträge klickt, und event.target sagt, welcher es war:
<ul id="tiere">
<li>Katze</li>
<li>Hund</li>
</ul>const tierListe = document.querySelector("#tiere");
tierListe.addEventListener("click", function (event) {
console.log(event.target.textContent);
});Ein Klick auf Hund gibt Hund aus. Der Handler hängt an der Liste, aber event.target ist der Eintrag, auf den geklickt wurde. Und es funktioniert auch für Einträge, die später zur Liste hinzukommen, ohne einen neuen Handler.
Es gibt einen Haken: event.target ist das innerste Element, auf das geklickt wurde. Wenn ein Eintrag weitere Elemente enthält, etwa <li><strong>Katze</strong>, 3 Jahre alt</li>, bekommst du bei einem Klick auf das Wort Katze das strong, nicht das li. Und bei einem Klick neben die Einträge, auf die Liste selbst, bekommst du das ul.
Die Methode closest() löst das. Du gibst ihr einen Selektor, wie du ihn querySelector() gibst. Sie beginnt beim Element selbst und geht durch die Elemente, in denen es steht, nach oben, bis sie eines findet, das passt:
tierListe.addEventListener("click", function (event) {
const eintrag = event.target.closest("li");
if (eintrag === null) {
return;
}
console.log(eintrag.textContent);
});Egal, wo im Eintrag du klickst, eintrag ist das li. Wenn der Klick nicht auf einen Eintrag ging, findet closest() nichts und gibt null zurück, und der Handler endet mit return. Ohne diese Prüfung würde eintrag.textContent mit dem Fehler TypeError: Cannot read properties of null (reading 'textContent') enden.
Die Einträge tragen ihre Daten meist in Daten-Attributen, etwa <li data-alter="3">, und der Handler liest sie mit eintrag.dataset.alter.
So schreibst du es:
Anweisungen
- 1
Gib
rezeptListeeinen Klick-Handler. Finde darin das angeklickte Rezept mitevent.target.closest("li")und beende den Handler, wenn es keines gibt. Zeige andernfalls die Zeit aus demdata-minutendes Rezepts inzeitTextan:Kochzeit: 15 Minutenfür die Pfannkuchen. Probiere aus, auf den Namen eines Rezepts und auf den Rest seiner Zeile zu klicken. - 2
Hebe das Rezept hervor, auf das geklickt wurde: Gib seinem
lidie Klassegewaehlt. Es ist immer nur ein Rezept hervorgehoben, also speichere den hervorgehobenen Eintrag in einer Variable (let gewaehltesRezept = null;, außerhalb des Handlers). Entferne vor dem Hervorheben eines neuen Rezepts die Klasse vom vorherigen, falls es eines gibt (gewaehltesRezeptist nichtnull), und speichere dann das neue in der Variable.