Hallo Linuchs
Und ja - ich habe vor einer Woche eine Lektion in Event-Handling bekommen, aber nicht verstanden, wie ich den "Absender" des onclick-Events erkenne. Das feuert ja in allen übergeordneten Tags.
Ich weiß, dass ich nicht besonders gut im Erklären bin, der von dir angesprochene Thread ist dafür ein trauriges Beispiel. In dieser Hinsicht wäre es aber auch für mich hilfreich gewesen, wenn du nochmals nachgefragt und dabei die einzelnen Stellen angesprochen hättest, die du nicht verstanden hast.
Mit „Absender“ des Ereignisses meinst du wohl das Element, bei dem das Ereignis eingetreten ist:
Das ist das Ziel (Target) des Ereignisses.
Wenn du das Objekt referenzieren willst, welches das Ziel eines Ereignisses ist, dann kannst du dies über die Eigenschaft target
des Event-Objektes machen:
<body>
<ul id="list">
<li>A</li>
<li>B</li>
<li>C</li>
</ul>
<script>
document.getElementById('list').addEventListener('click', function (event) {
if (event.target !== this) {
console.log(event.target.textContent); // A oder B oder C
}
});
</script>
</body>
Hier ist ein Eventhandler für das Objekt registriert, welches das ul
-Element mit der ID list
repräsentiert, und zwar für das Ereignis click
. Dieser Eventhandler wird nun immer dann aufgerufen wenn entweder auf das Listenelement selbst, oder aber auf eines seiner Kindelemente geklickt wird.
Für die anonyme Funktion die wir der Methode addEventListener
hier als zweites Argument übergeben ist ein Parameter event
deklariert. Wenn nun die Funktion bei einem Klick innerhalb der Liste aufgerufen wird, dann wird bei diesem Aufruf das Event-Objekt als Argument übergeben, sodass dieses innerhalb der Funktion über event
referenziert werden kann.
Der Wert der Eigenschaft target
des Event-Objektes ist nun wie gesagt immer eine Referenz auf das Objekt, bei dem das Ereignis eingetreten ist. Das bedeutet, hier im Beispiel verweist event.target
entweder auf das Listenelement selbst, für das wir den Eventhandler registriert haben, oder aber auf eines der Kindelemente der Liste, eben abhängig davon, auf welches der Elemente tatsächlich geklickt wurde.
Die Variable this
hingegen, ebenso wie die Eigenschaft event.currentTarget
enthält immer eine Referenz auf das Objekt für welches der aufgerufene Eventhandler registriert wurde. Wenn wir also prüfen
if (event.target !== this)
dann heißt das soviel wie: „Wenn das Element auf das geklickt wurde nicht das Element ist, für das dieser Eventhander registriert wurde, dann führe die folgende Anweisung aus.“
Wir hätten an dieser Stelle also ebenso gut schreiben können
if (event.target !== event.currentTarget)
oder auch
if (event.target !== document.getElementById('list'))
Da wir das Element ul
, für welches wir den Handler registriert haben, durch diese bedingte Anweisung ausgeschlossen haben, wird also nur dann der textuelle Inhalt des Zielobjektes in die Konsole geschrieben, wenn auf eines der li
-Elemente geklickt wurde. Sonst passiert nichts.
console.log(event.target.textContent); // A oder B oder C
Das meinte ich im Übrigen mit „in der Handlerfunktion selektieren“: Den Wert der Eigenschaft target
des Event-Objektes lesen und dann abhängig von dem dort referenzierten Zielobjekt die verschiedenen Anweisungen ausführen.
Drehen wir unser Beispiel einmal um und nehmen an, wir wollten nur dann etwas machen, wenn das Ereignis tatsächlich bei dem ul
-Element aufgetreten ist, nicht aber bei einem seiner Kindelemente:
<body>
<ul id="list">
<li>A</li>
<li>B</li>
<li>C</li>
</ul>
<script>
document.getElementById('list').addEventListener('click', function (event) {
if (event.target.parentElement === document.body) {
console.log(event.target.tagName); // UL
}
});
</script>
</body>
Auch hier ist wieder ein Eventhandler für das ul
-Element mit der ID list
registriert, und auch hier verwenden wir event.target
, um das Element zu identifizieren, auf das tatsächlich geklickt wurde.
if (event.target.parentElement === document.body) {
console.log(event.target.tagName); // UL
}
Hier prüfen wir, ob das Elternelement des Elementes auf das geklickt wurde das body
-Element ist. Da das Elternelement der li
-Elemente hier natürlich nicht body
sondern ul
ist, wird die nachfolgende Anweisung nur ausgeführt, wenn auf das Listenelement selbst geklickt wurde.
Wobei wir bezogen auf dieses konkrete Beispiel freilich besser so geprüft hätten (siehe oben):
if (event.target === this)
// oder
if (event.target === event.currentTarget)
Wandeln wir das Beispiel nochmals etwas ab, sodass es dem Code recht ähnlich ist, den du im ersten Beitrag des eingangs verlinkten Threads gepostet hattest:
<body>
<ul id="list">
<li>A</li>
<li>B</li>
<li>
<ul class="sub">
<li>C</li>
<li>D</li>
</ul>
</li>
</ul>
<script>
document.getElementById('list').addEventListener('click', function (event) {
var target = event.target, parent = target.parentElement;
if (parent === this && !target.children[0]) {
console.log('click on list level one item');
}
else if (parent.className === 'sub') {
console.log('click on list level two item');
}
});
</script>
</body>
Auch hier wird wieder über event.target
selektiert:
Die erste bedingte Anweisung wird nur dann ausgeführt, wenn auf ein Kindelement von list
geklickt wurde, das nicht selbst über ein Kindelement verfügt. Hier also die ersten beiden li
-Elemente mit dem Inhalt A
und B
. Die zweite bedingte Anweisung wird entsprechend nur dann ausgeführt, wenn auf eines der beiden Kindelemente des zweiten ul
-Elementes mit der Klasse sub
geklickt wurde.
Hierbei sei übrigens besonderes Augenmerk auf den zweiten Teil der ersten Bedingung gerichtet:
Im Gegensatz zu deinem Beispielcode habe ich hier nicht die Eigenschaft childNodes
gelesen sondern die Eigenschaft children
. In childNodes
sind nämlich anders als in children
nicht nur Elementknoten enthalten sondern ebenfalls Textknoten, und das hätte uns hier natürlich nicht weitergeholfen.
Das wäre nun jedenfalls ein Beispiel für das Prinzip der Event Delegation, denn die Behandlung von Ereignissen, die bei verschiedenen Elementen eintreten, wird hier an eine einzige Handlerfunktion delegiert, welche für ein gemeinsames Elternelement registriert wurde.
Ich hoffe ich konnte dir nun zumindest diesen Punkt verständlich machen. Wenn nicht, wirst du dir wohl jemanden suchen müssen der das besser erklären kann als ich. :-/
Viele Grüße,
Orlok