Es ist schön, wenn es einen Link zu einer nützlichen Informationsquelle gibt. 6 Stunden später ist dies der Google-Top-Hit für "Dom Event Delegation". Vielleicht ist dies ein nützlicher Link? Ich bin nicht ganz sicher: w3.org/TR/DOM-Level-2-Events/events.html
Die DOM-Ereignisdelegation ist ein Mechanismus zum Reagieren auf UI-Ereignisse über einen einzigen gemeinsamen Elternteil und nicht über jedes Kind, durch die Magie des "Sprudelns" des Ereignisses (auch bekannt als Ereignisausbreitung).
Das Ereignis wird an sein Ziel gesendet
EventTargetund alle dort gefundenen Ereignis-Listener werden ausgelöst. Bubbling-
Ereignisse lösen dann alle zusätzlichen Ereignis-Listener aus, die gefunden werden, indem Sie der EventTargetübergeordneten Kette des Ereignisses nach oben folgen und nach Ereignis-Listenern suchen, die in jedem aufeinanderfolgenden EventTarget registriert sind. Diese Ausbreitung nach oben wird bis einschließlich der Document.
Das Bubbling von Ereignissen bildet die Grundlage für die Ereignisdelegierung in Browsern. Jetzt können Sie einen Ereignishandler an ein einzelnes übergeordnetes Element binden. Dieser Handler wird ausgeführt, wenn das Ereignis auf einem seiner untergeordneten Knoten (und einem seiner untergeordneten Knoten) auftritt . Dies ist eine Ereignisdelegation. Hier ist ein Beispiel dafür in der Praxis:
Wenn Sie in diesem Beispiel auf einen der untergeordneten <li>Knoten klicken , wird eine Warnung angezeigt "click!", obwohl kein Klick-Handler an den <li>angeklickten Knoten gebunden ist . Wenn wir an onclick="..."jeden gebunden <li>wären, würden Sie den gleichen Effekt erzielen.
Was ist der Vorteil?
Stellen Sie sich vor, Sie müssen jetzt <li>über die DOM-Manipulation dynamisch neue Elemente zur obigen Liste hinzufügen :
var newLi = document.createElement('li');
newLi.innerHTML ='Four';
myUL.appendChild(newLi);
Ohne Ereignisdelegierung müssten Sie den "onclick"Ereignishandler erneut an das neue <li>Element binden , damit er sich wie seine Geschwister verhält . Mit der Ereignisdelegierung müssen Sie nichts tun. Fügen Sie einfach das Neue <li>zur Liste hinzu und Sie sind fertig.
Dies ist absolut fantastisch für Web-Apps mit Event-Handlern, die an viele Elemente gebunden sind und in denen neue Elemente dynamisch im DOM erstellt und / oder entfernt werden. Mit der Ereignisdelegierung kann die Anzahl der Ereignisbindungen drastisch verringert werden, indem sie in ein gemeinsames übergeordnetes Element verschoben werden, und Code, der im laufenden Betrieb dynamisch neue Elemente erstellt, kann von der Logik der Bindung ihrer Ereignishandler entkoppelt werden.
Ein weiterer Vorteil der Ereignisdelegierung besteht darin, dass der gesamte Speicherbedarf, der von Ereignis-Listenern verwendet wird, abnimmt (da die Anzahl der Ereignisbindungen abnimmt). Bei kleinen Seiten, die häufig entladen werden (dh, der Benutzer navigiert häufig zu verschiedenen Seiten), macht dies möglicherweise keinen großen Unterschied. Für langlebige Anwendungen kann dies jedoch von Bedeutung sein. Es gibt einige wirklich schwer auffindbare Situationen, in denen Elemente, die aus dem DOM entfernt wurden, immer noch Speicher beanspruchen (dh sie lecken), und häufig ist dieser durchgesickerte Speicher an eine Ereignisbindung gebunden. Mit der Ereignisdelegierung können Sie untergeordnete Elemente zerstören, ohne das Risiko zu vergessen, die Ereignis-Listener zu "entbinden" (da sich der Listener auf dem Vorfahren befindet). Diese Arten von Speicherlecks können dann eingedämmt werden (wenn sie nicht beseitigt werden, was manchmal verdammt schwer zu tun ist. IE, ich sehe dich an).
Hier sind einige bessere konkrete Codebeispiele für die Ereignisdelegierung:
Gute Antwort! Ich war lange Zeit verwirrt darüber, aber dieses Beispiel machte es mir kristallklar.
Cofey
Ich habe keinen Zugriff beim Öffnen Ihres dritten Links. Ereignisdelegation ohne Javascript-Bibliothek und +1 für Ihren letzten Link
bugwheels94
Hallo, danke für eine tolle Erklärung. Ich bin jedoch immer noch verwirrt über ein bestimmtes Detail: Wie ich den Ereignisfluss im DOM-Baum verstehe (wie in 3.1 zu sehen ist . Ereignisversand und DOM-Ereignisfluss ), breitet sich das Ereignisobjekt aus, bis es das Zielelement erreicht, und sprudelt dann hoch. Wie kommt es, dass untergeordnete Elemente eines Knotens erreicht werden können, wenn das übergeordnete Element dieses Knotens das betreffende Ereignisziel ist? zB wie kann sich das Ereignis zu einem <li>Zeitpunkt ausbreiten, an dem es anhalten soll <ul>? Wenn meine Frage noch unklar ist oder einen separaten Thread benötigt, würde ich mich freuen, sie zu verpflichten.
Aetos
@Aetos: > Wie kommt es, dass untergeordnete Elemente eines Knotens erreicht werden können, wenn das übergeordnete Element dieses Knotens das betreffende Ereignisziel ist? Es kann nicht, wie ich es verstehe. Das Ereignis beendet Phase 1 (Erfassung) am übergeordneten Ziel, tritt in Phase 2 (Ziel) am Ziel selbst ein und tritt dann in Phase 3 (Sprudeln) ein, beginnend am übergeordneten Ziel. Nirgendwo erreicht es ein Kind des Ziels.
Crescent Fresh
1
Wirklich tolle Antwort. Vielen Dank, dass Sie die Delegation von Veranstaltungen mit relevanten Fakten erklärt haben. Vielen Dank!
Kshitij Tiwari
30
Mit der Ereignisdelegierung können Sie vermeiden, bestimmten Knoten Ereignis-Listener hinzuzufügen. Stattdessen wird der Ereignis-Listener einem übergeordneten Element hinzugefügt. Dieser Ereignis-Listener analysiert sprudelnde Ereignisse, um eine Übereinstimmung mit untergeordneten Elementen zu finden.
JavaScript Beispiel:
Angenommen, wir haben ein übergeordnetes UL-Element mit mehreren untergeordneten Elementen:
Nehmen wir auch an, dass etwas passieren muss, wenn auf jedes untergeordnete Element geklickt wird. Sie können jedem einzelnen LI-Element einen separaten Ereignis-Listener hinzufügen. Was ist jedoch, wenn LI-Elemente häufig hinzugefügt und aus der Liste entfernt werden? Das Hinzufügen und Entfernen von Ereignis-Listenern wäre ein Albtraum, insbesondere wenn sich der Code zum Hinzufügen und Entfernen an verschiedenen Stellen in Ihrer App befindet. Die bessere Lösung besteht darin, dem übergeordneten UL-Element einen Ereignis-Listener hinzuzufügen. Wenn Sie jedoch den Ereignis-Listener zum übergeordneten Element hinzufügen, woher wissen Sie dann, auf welches Element geklickt wurde?
Einfach: Wenn das Ereignis zum UL-Element sprudelt, überprüfen Sie die Zieleigenschaft des Ereignisobjekts, um einen Verweis auf den tatsächlich angeklickten Knoten zu erhalten. Hier ist ein sehr einfaches JavaScript-Snippet, das die Ereignisdelegierung veranschaulicht:
// Get the element, add a click listener...
document.getElementById("parent-list").addEventListener("click",function(e){// e.target is the clicked element!// If it was a list itemif(e.target && e.target.nodeName =="LI"){// List item found! Output the ID!
console.log("List item ", e.target.id.replace("post-")," was clicked!");}});
Fügen Sie dem übergeordneten Element zunächst einen Listener für Klickereignisse hinzu. Wenn der Ereignis-Listener ausgelöst wird, überprüfen Sie das Ereigniselement, um sicherzustellen, dass es der Elementtyp ist, auf den reagiert werden soll. Wenn es ein LI-Element ist, boom: Wir haben, was wir brauchen! Wenn es sich nicht um ein Element handelt, das wir möchten, kann das Ereignis ignoriert werden. Dieses Beispiel ist ziemlich einfach - UL und LI sind ein direkter Vergleich. Versuchen wir etwas Schwierigeres. Lassen Sie uns einen Eltern-DIV mit vielen Kindern haben, aber alles, was uns wichtig ist, ist ein A-Tag mit der Klasse-CSS-Klasse:
// Get the parent DIV, add click listener...
document.getElementById("myDiv").addEventListener("click",function(e){// e.target was the clicked elementif(e.target && e.target.nodeName =="A"){// Get the CSS classesvar classes = e.target.className.split(" ");// Search for the CSS class!if(classes){// For every CSS class the element has...for(var x =0; x < classes.length; x++){// If it has the CSS class we want...if(classes[x]=="classA"){// Bingo!
console.log("Anchor element clicked!");// Now do something here....}}}}});
Die Delegation von Dom-Events unterscheidet sich von der Definition der Informatik.
Es bezieht sich auf die Behandlung von sprudelnden Ereignissen aus vielen Elementen, wie z. B. Tabellenzellen, aus einem übergeordneten Objekt wie der Tabelle. Dies kann den Code einfacher halten, insbesondere beim Hinzufügen oder Entfernen von Elementen, und spart Speicherplatz.
Die Delegierung ist eine Technik, bei der ein Objekt ein bestimmtes Verhalten nach außen ausdrückt, in Wirklichkeit jedoch die Verantwortung für die Implementierung dieses Verhaltens an ein zugeordnetes Objekt delegiert. Dies klingt zunächst sehr ähnlich wie das Proxy-Muster, dient jedoch einem ganz anderen Zweck. Die Delegierung ist ein Abstraktionsmechanismus, der das Verhalten von Objekten (Methoden) zentralisiert.
Allgemein gesprochen: Verwenden Sie die Delegierung als Alternative zur Vererbung. Vererbung ist eine gute Strategie, wenn eine enge Beziehung zwischen übergeordnetem und untergeordnetem Objekt besteht, Vererbung jedoch Objekte sehr eng koppelt. Delegation ist häufig die flexiblere Möglichkeit, eine Beziehung zwischen Klassen auszudrücken.
Dieses Muster wird auch als "Proxy-Ketten" bezeichnet. Einige andere Entwurfsmuster verwenden die Delegierung - die Status-, Strategie- und Besuchermuster hängen davon ab.
Gute Erklärung. Im Beispiel des <ul> mit mehreren <li> Kindern sind es anscheinend diejenigen, die mit der Klicklogik umgehen, aber das ist nicht so, weil sie diese Logik im Vater <ul>
Juanma Menendez
6
Das Delegationskonzept
Wenn sich in einem übergeordneten Element viele Elemente befinden und Sie Ereignisse für diese Elemente verarbeiten möchten, binden Sie keine Handler an jedes Element. Binden Sie stattdessen den einzelnen Handler an das übergeordnete Element und rufen Sie das untergeordnete Element aus event.target ab. Diese Site bietet nützliche Informationen zum Implementieren der Ereignisdelegierung.
http://javascript.info/tutorial/event-delegation
Bei der Ereignisdelegierung wird ein Ereignis behandelt, das mithilfe eines Ereignishandlers für ein Containerelement sprudelt , das Verhalten des Ereignishandlers jedoch nur aktiviert, wenn das Ereignis für ein Element im Container aufgetreten ist, das einer bestimmten Bedingung entspricht. Dies kann die Behandlung von Ereignissen für Elemente im Container vereinfachen.
Angenommen, Sie möchten einen Klick auf eine Tabellenzelle in einer großen Tabelle ausführen. Sie können eine Schleife schreiben, um einen Klick-Handler an jede Zelle anzuschließen ... oder Sie können einen Klick-Handler an die Tabelle anschließen und die Ereignisdelegierung verwenden, um sie nur für Tabellenzellen (und nicht für Tabellenüberschriften oder das Leerzeichen in a) auszulösen Reihe um Zellen usw.).
Dies ist auch nützlich, wenn Sie Elemente zum Container hinzufügen und daraus entfernen möchten, da Sie sich nicht um das Hinzufügen und Entfernen von Ereignishandlern für diese Elemente kümmern müssen. Haken Sie das Ereignis einfach in den Container ein und behandeln Sie das Ereignis, wenn es sprudelt.
Hier ist ein einfaches Beispiel (es ist absichtlich ausführlich, um eine Inline-Erklärung zu ermöglichen): Behandeln eines Klicks auf ein tdElement in einer Containertabelle:
// Handle the event on the container
document.getElementById("container").addEventListener("click",function(event){// Find out if the event targeted or bubbled through a `td` en route to this container elementvar element = event.target;var target;while(element &&!target){if(element.matches("td")){// Found a `td` within the container!
target = element;}else{// Not foundif(element ===this){// We've reached the container, stop
element =null;}else{// Go to the next parent in the ancestry
element = element.parentNode;}}}if(target){
console.log("You clicked a td: "+ target.textContent);}else{
console.log("That wasn't a td in the container table");}});
Bevor wir auf die Details eingehen, möchten wir uns daran erinnern, wie DOM-Ereignisse funktionieren.
DOM-Ereignisse werden vom Dokument an das Zielelement (die Erfassungsphase ) gesendet und dann vom Zielelement zurück zum Dokument (die Blasenphase ) geleitet. Diese Grafik in der alten DOM3-Ereignisspezifikation (jetzt ersetzt, aber die Grafik ist noch gültig) zeigt es wirklich gut:
Nicht alle Ereignisse sprudeln, aber die meisten, einschließlich click.
Die Kommentare im obigen Codebeispiel beschreiben, wie es funktioniert. matchesprüft, ob ein Element mit einem CSS-Selektor übereinstimmt, aber Sie können natürlich auch prüfen, ob etwas Ihren Kriterien auf andere Weise entspricht, wenn Sie keinen CSS-Selektor verwenden möchten.
Dieser Code wird geschrieben verbosely die einzelnen Schritte zu rufen, sondern auf vage modernen Browsern (und auf IE auch wenn Sie eine polyfill verwenden), können Sie verwenden , closestund containsstatt der Schleife:
var target = event.target.closest("td");
console.log("You clicked a td: "+ target.textContent);}else{
console.log("That wasn't a td in the container table");}
// Handle the event on the container
document.getElementById("container").addEventListener("click",function(event){var target = event.target.closest("td");if(target &&this.contains(target)){
console.log("You clicked a td: "+ target.textContent);}else{
console.log("That wasn't a td in the container table");}});
closestÜberprüft das Element, auf das Sie es aufrufen, um festzustellen, ob es mit dem angegebenen CSS-Selektor übereinstimmt, und gibt in diesem Fall dasselbe Element zurück. Wenn nicht, überprüft es das übergeordnete Element, um festzustellen, ob es übereinstimmt, und gibt das übergeordnete Element zurück, wenn dies der Fall ist. Wenn nicht, überprüft es das übergeordnete Element des Elternteils usw. Es findet also das "nächstgelegene" Element in der Ahnenliste, das dem Selektor entspricht. Da dies möglicherweise über das Containerelement hinausgeht, containsüberprüft der obige Code , ob sich ein passendes Element im Container befindet. Wenn Sie das Ereignis in den Container einbinden, haben Sie angegeben, dass Sie nur Elemente in diesem Container behandeln möchten .
Zurück zu unserem Tabellenbeispiel: Wenn Sie eine Tabelle in einer Tabellenzelle haben, stimmt diese nicht mit der Tabellenzelle überein, die die Tabelle enthält:
// Handle the event on the container
document.getElementById("container").addEventListener("click",function(event){var target = event.target.closest("td");if(target &&this.contains(target)){
console.log("You clicked a td: "+ target.textContent);}else{
console.log("That wasn't a td in the container table");}});
<!-- The table wrapped around the #container table --><table><tbody><tr><td><!-- This cell doesn't get matched, thanks to the `this.contains(target)` check --><tableid="container"><thead><tr><th>Language</th><th>1</th><th>2</th><th>3</th></tr></thead><tbody><tr><thclass="rowheader">English</th><td>one</td><td>two</td><td>three</td></tr><tr><thclass="rowheader">Español</th><td>uno</td><td>dos</td><td>tres</td></tr><tr><thclass="rowheader">Italiano</th><td>uno</td><td>due</td><td>tre</td></tr></tbody></table></td><td>
This is next to the container table
</td></tr></tbody></table>
Es ist im Grunde, wie die Assoziation mit dem Element hergestellt wird. .clickgilt für das aktuelle DOM, während .on(unter Verwendung der Delegierung) weiterhin für neue Elemente gültig ist, die dem DOM nach der Ereigniszuordnung hinzugefügt wurden.
Was besser zu benutzen ist, würde ich sagen, es hängt vom Fall ab.
Um die Ereignisdelegierung zuerst zu verstehen, müssen wir wissen, warum und wann wir die Ereignisdelegierung tatsächlich benötigen oder wollen.
Es mag viele Fälle geben, aber lassen Sie uns zwei große Anwendungsfälle für die Ereignisdelegation diskutieren. 1. Der erste Fall ist, wenn wir ein Element mit vielen untergeordneten Elementen haben, an denen wir interessiert sind. In diesem Fall fügen wir, anstatt allen diesen untergeordneten Elementen einen Ereignishandler hinzuzufügen, ihn einfach dem übergeordneten Element hinzu und bestimmen dann Auf welches untergeordnete Element wurde das Ereignis ausgelöst?
2. Der zweite Anwendungsfall für die Ereignisdelegierung besteht darin, dass ein Ereignishandler an ein Element angehängt werden soll, das sich beim Laden unserer Seite noch nicht im DOM befindet. Das liegt natürlich daran, dass wir einem Ereignishandler, der nicht auf unserer Seite ist, keinen Ereignishandler hinzufügen können, also im Falle eines Verfalls, den wir codieren.
Angenommen, Sie haben eine Liste mit 0, 10 oder 100 Elementen im DOM, wenn Sie Ihre Seite laden, und weitere Elemente warten in Ihrer Hand darauf, in die Liste aufgenommen zu werden. Es gibt also keine Möglichkeit, einen Ereignishandler für zukünftige Elemente anzuhängen, oder diese Elemente werden noch nicht im DOM hinzugefügt, und es können auch viele Elemente vorhanden sein. Daher wäre es nicht sinnvoll, jeweils einen Ereignishandler anzuhängen von ihnen.
Ereignisdelegation
Also gut, um über Eventdelegation zu sprechen, ist das erste Konzept, über das wir tatsächlich sprechen müssen, das Sprudeln von Events.
Ereignisblasen:
Ereignisblasen bedeutet, dass, wenn ein Ereignis für ein DOM-Element ausgelöst oder ausgelöst wird, beispielsweise durch Klicken auf unsere Schaltfläche hier im folgenden Bild, genau dasselbe Ereignis auch für alle übergeordneten Elemente ausgelöst wird.
Das Ereignis wird zuerst auf die Schaltfläche ausgelöst, dann aber auch nacheinander auf alle übergeordneten Elemente, sodass es auch auf den Absatz des Abschnitts des Hauptelements und tatsächlich ganz oben in einem DOM-Baum ausgelöst wird bis zum HTML-Element, das die Wurzel ist. Wir sagen also, dass das Ereignis im DOM-Baum in die Luft sprudelt, und deshalb wird es als Sprudeln bezeichnet.
Zielelement: Das Element, auf das das Ereignis tatsächlich zum ersten Mal ausgelöst wurde, wird als Zielelement bezeichnet. Das Element, das das Ereignis verursacht hat, wird als Zielelement bezeichnet. In unserem obigen Beispiel hier ist es natürlich die Schaltfläche, auf die geklickt wurde. Der wichtige Teil ist, dass dieses Zielelement als Eigenschaft im Ereignisobjekt gespeichert wird. Dies bedeutet, dass alle übergeordneten Elemente, auf die das Ereignis auch ausgelöst wird, das Zielelement des Ereignisses kennen, also wo das Ereignis zuerst ausgelöst wurde.
Das bringt uns zur Ereignisdelegierung, denn wenn das Ereignis im DOM-Baum sprudelt und wir wissen, wo das Ereignis ausgelöst wurde, können wir einfach einen Ereignishandler an ein übergeordnetes Element anhängen und warten, bis das Ereignis sprudelt, und wir können Machen Sie dann alles, was wir mit unserem Zielelement vorhaben. Diese Technik wird als Ereignisdelegation bezeichnet. In diesem Beispiel hier könnten wir einfach den Ereignishandler zum Hauptelement hinzufügen.
Also gut, die Ereignisdelegation besteht darin, den Ereignishandler nicht für das ursprüngliche Element einzurichten, an dem wir interessiert sind, sondern ihn an ein übergeordnetes Element anzuhängen und das Ereignis dort im Grunde zu erfassen, weil es sprudelt. Wir können dann auf das Element einwirken, an dem wir interessiert sind, indem wir die Zielelement-Eigenschaft verwenden.
Beispiel:
Nehmen wir nun an, wir haben zwei Listenelemente auf unserer Seite. Nachdem wir Elemente in dieser Liste programmgesteuert hinzugefügt haben, möchten wir ein oder mehrere Elemente aus ihnen löschen. Mit der Technik der Ereignisdelegation können wir unseren Zweck leicht erreichen.
<div class="body"><div class="top"></div><div class="bottom"><div class="other"><!-- other bottom elements --></div><div class="container clearfix"><div class="income"><h2 class="icome__title">Income</h2><div class="income__list"><!-- list items --></div></div><div class="expenses"><h2 class="expenses__title">Expenses</h2><div class="expenses__list"><!-- list items --></div></div></div></div></div>
Hinzufügen von Elementen zu dieser Liste:
constDOMstrings={
type:{
income:'inc',
expense:'exp'},
incomeContainer:'.income__list',
expenseContainer:'.expenses__list',
container:'.container'}var addListItem =function(obj, type){//create html string with the place holdervar html, element;if(type===DOMstrings.type.income){
element =DOMstrings.incomeContainer
html =`<div class="item clearfix" id="inc-${obj.id}"><div class="item__description">${obj.descripiton}</div><div class="right clearfix"><div class="item__value">${obj.value}</div><div class="item__delete"><button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button></div></div></div>`}elseif(type ===DOMstrings.type.expense){
element=DOMstrings.expenseContainer;
html =`<div class="item clearfix" id="exp-${obj.id}"><div class="item__description">${obj.descripiton}</div><div class="right clearfix"><div class="item__value">${obj.value}</div><div class="item__percentage">21%</div><div class="item__delete"><button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button></div></div></div>`}var htmlObject = document.createElement('div');
htmlObject.innerHTML=html;
document.querySelector(element).insertAdjacentElement('beforeend', htmlObject);}
Elemente löschen:
var ctrlDeleteItem =function(event){// var itemId = event.target.parentNode.parentNode.parentNode.parentNode.id;var parent = event.target.parentNode;var splitId, type, ID;while(parent.id===""){
parent = parent.parentNode
}if(parent.id){
splitId = parent.id.split('-');
type = splitId[0];
ID=parseInt(splitId[1]);}
deleteItem(type, ID);
deleteListItem(parent.id);}var deleteItem =function(type, id){var ids, index;
ids = data.allItems[type].map(function(current){return current.id;});
index = ids.indexOf(id);if(index>-1){
data.allItems[type].splice(index,1);}}var deleteListItem =function(selectorID){var element = document.getElementById(selectorID);
element.parentNode.removeChild(element);}
Ein Delegat in C # ähnelt einem Funktionszeiger in C oder C ++. Durch die Verwendung eines Delegaten kann der Programmierer einen Verweis auf eine Methode in einem Delegatenobjekt kapseln. Das Delegatenobjekt kann dann an Code übergeben werden, der die referenzierte Methode aufrufen kann, ohne zur Kompilierungszeit wissen zu müssen, welche Methode aufgerufen wird.
Ich werde dies nicht ablehnen, da es wahrscheinlich eine korrekte Antwort auf die ursprüngliche Frage war, aber die Frage
bezieht
1
Bei der Ereignisdelegierung werden zwei häufig übersehene Funktionen von JavaScript-Ereignissen verwendet: Ereignisblasen und das Zielelement. Wenn ein Ereignis für ein Element ausgelöst wird, z. B. ein Mausklick auf eine Schaltfläche, wird dasselbe Ereignis auch für alle Vorfahren dieses Elements ausgelöst . Dieser Vorgang wird als Ereignisblasen bezeichnet. Das Ereignis sprudelt vom Ursprungselement zum oberen Rand des DOM-Baums.
Stellen Sie sich eine HTML-Tabelle mit 10 Spalten und 100 Zeilen vor, in der etwas passieren soll, wenn der Benutzer auf eine Tabellenzelle klickt. Zum Beispiel musste ich einmal jede Zelle einer Tabelle dieser Größe beim Klicken bearbeitbar machen. Das Hinzufügen von Ereignishandlern zu jeder der 1000 Zellen wäre ein großes Leistungsproblem und möglicherweise eine Ursache für Speicherverluste beim Absturz des Browsers. Stattdessen würden Sie mithilfe der Ereignisdelegierung nur einen Ereignishandler zum Tabellenelement hinzufügen, das Klickereignis abfangen und bestimmen, auf welche Zelle geklickt wurde.
Hängen Sie einen Ereignis-Listener an ein übergeordnetes Element an, das ausgelöst wird, wenn ein Ereignis für ein untergeordnetes Element auftritt.
Ereignisausbreitung
Wenn ein Ereignis durch das DOM vom untergeordneten zum übergeordneten Element verschoben wird, wird dies als Ereignisausbreitung bezeichnet , da sich das Ereignis ausbreitet oder durch das DOM bewegt.
In diesem Beispiel wird ein Ereignis (onclick) von einer Schaltfläche an den übergeordneten Absatz übergeben.
$(document).ready(function(){
$(".spoiler span").hide();/* add event onclick on parent (.spoiler) and delegate its event to child (button) */
$(".spoiler").on("click","button",function(){
$(".spoiler button").hide();
$(".spoiler span").show();});});
Antworten:
Die DOM-Ereignisdelegation ist ein Mechanismus zum Reagieren auf UI-Ereignisse über einen einzigen gemeinsamen Elternteil und nicht über jedes Kind, durch die Magie des "Sprudelns" des Ereignisses (auch bekannt als Ereignisausbreitung).
Wenn ein Ereignis für ein Element ausgelöst wird, tritt Folgendes auf :
Das Bubbling von Ereignissen bildet die Grundlage für die Ereignisdelegierung in Browsern. Jetzt können Sie einen Ereignishandler an ein einzelnes übergeordnetes Element binden. Dieser Handler wird ausgeführt, wenn das Ereignis auf einem seiner untergeordneten Knoten (und einem seiner untergeordneten Knoten) auftritt . Dies ist eine Ereignisdelegation. Hier ist ein Beispiel dafür in der Praxis:
Wenn Sie in diesem Beispiel auf einen der untergeordneten
<li>
Knoten klicken , wird eine Warnung angezeigt"click!"
, obwohl kein Klick-Handler an den<li>
angeklickten Knoten gebunden ist . Wenn wir anonclick="..."
jeden gebunden<li>
wären, würden Sie den gleichen Effekt erzielen.Was ist der Vorteil?
Stellen Sie sich vor, Sie müssen jetzt
<li>
über die DOM-Manipulation dynamisch neue Elemente zur obigen Liste hinzufügen :Ohne Ereignisdelegierung müssten Sie den
"onclick"
Ereignishandler erneut an das neue<li>
Element binden , damit er sich wie seine Geschwister verhält . Mit der Ereignisdelegierung müssen Sie nichts tun. Fügen Sie einfach das Neue<li>
zur Liste hinzu und Sie sind fertig.Dies ist absolut fantastisch für Web-Apps mit Event-Handlern, die an viele Elemente gebunden sind und in denen neue Elemente dynamisch im DOM erstellt und / oder entfernt werden. Mit der Ereignisdelegierung kann die Anzahl der Ereignisbindungen drastisch verringert werden, indem sie in ein gemeinsames übergeordnetes Element verschoben werden, und Code, der im laufenden Betrieb dynamisch neue Elemente erstellt, kann von der Logik der Bindung ihrer Ereignishandler entkoppelt werden.
Ein weiterer Vorteil der Ereignisdelegierung besteht darin, dass der gesamte Speicherbedarf, der von Ereignis-Listenern verwendet wird, abnimmt (da die Anzahl der Ereignisbindungen abnimmt). Bei kleinen Seiten, die häufig entladen werden (dh, der Benutzer navigiert häufig zu verschiedenen Seiten), macht dies möglicherweise keinen großen Unterschied. Für langlebige Anwendungen kann dies jedoch von Bedeutung sein. Es gibt einige wirklich schwer auffindbare Situationen, in denen Elemente, die aus dem DOM entfernt wurden, immer noch Speicher beanspruchen (dh sie lecken), und häufig ist dieser durchgesickerte Speicher an eine Ereignisbindung gebunden. Mit der Ereignisdelegierung können Sie untergeordnete Elemente zerstören, ohne das Risiko zu vergessen, die Ereignis-Listener zu "entbinden" (da sich der Listener auf dem Vorfahren befindet). Diese Arten von Speicherlecks können dann eingedämmt werden (wenn sie nicht beseitigt werden, was manchmal verdammt schwer zu tun ist. IE, ich sehe dich an).
Hier sind einige bessere konkrete Codebeispiele für die Ereignisdelegierung:
focus
undblur
Ereignisse (die nicht sprudeln) aufgedecktquelle
<li>
Zeitpunkt ausbreiten, an dem es anhalten soll<ul>
? Wenn meine Frage noch unklar ist oder einen separaten Thread benötigt, würde ich mich freuen, sie zu verpflichten.Mit der Ereignisdelegierung können Sie vermeiden, bestimmten Knoten Ereignis-Listener hinzuzufügen. Stattdessen wird der Ereignis-Listener einem übergeordneten Element hinzugefügt. Dieser Ereignis-Listener analysiert sprudelnde Ereignisse, um eine Übereinstimmung mit untergeordneten Elementen zu finden.
JavaScript Beispiel:
Angenommen, wir haben ein übergeordnetes UL-Element mit mehreren untergeordneten Elementen:
Nehmen wir auch an, dass etwas passieren muss, wenn auf jedes untergeordnete Element geklickt wird. Sie können jedem einzelnen LI-Element einen separaten Ereignis-Listener hinzufügen. Was ist jedoch, wenn LI-Elemente häufig hinzugefügt und aus der Liste entfernt werden? Das Hinzufügen und Entfernen von Ereignis-Listenern wäre ein Albtraum, insbesondere wenn sich der Code zum Hinzufügen und Entfernen an verschiedenen Stellen in Ihrer App befindet. Die bessere Lösung besteht darin, dem übergeordneten UL-Element einen Ereignis-Listener hinzuzufügen. Wenn Sie jedoch den Ereignis-Listener zum übergeordneten Element hinzufügen, woher wissen Sie dann, auf welches Element geklickt wurde?
Einfach: Wenn das Ereignis zum UL-Element sprudelt, überprüfen Sie die Zieleigenschaft des Ereignisobjekts, um einen Verweis auf den tatsächlich angeklickten Knoten zu erhalten. Hier ist ein sehr einfaches JavaScript-Snippet, das die Ereignisdelegierung veranschaulicht:
Fügen Sie dem übergeordneten Element zunächst einen Listener für Klickereignisse hinzu. Wenn der Ereignis-Listener ausgelöst wird, überprüfen Sie das Ereigniselement, um sicherzustellen, dass es der Elementtyp ist, auf den reagiert werden soll. Wenn es ein LI-Element ist, boom: Wir haben, was wir brauchen! Wenn es sich nicht um ein Element handelt, das wir möchten, kann das Ereignis ignoriert werden. Dieses Beispiel ist ziemlich einfach - UL und LI sind ein direkter Vergleich. Versuchen wir etwas Schwierigeres. Lassen Sie uns einen Eltern-DIV mit vielen Kindern haben, aber alles, was uns wichtig ist, ist ein A-Tag mit der Klasse-CSS-Klasse:
http://davidwalsh.name/event-delegate
quelle
Die Delegation von Dom-Events unterscheidet sich von der Definition der Informatik.
Es bezieht sich auf die Behandlung von sprudelnden Ereignissen aus vielen Elementen, wie z. B. Tabellenzellen, aus einem übergeordneten Objekt wie der Tabelle. Dies kann den Code einfacher halten, insbesondere beim Hinzufügen oder Entfernen von Elementen, und spart Speicherplatz.
quelle
Die Delegierung ist eine Technik, bei der ein Objekt ein bestimmtes Verhalten nach außen ausdrückt, in Wirklichkeit jedoch die Verantwortung für die Implementierung dieses Verhaltens an ein zugeordnetes Objekt delegiert. Dies klingt zunächst sehr ähnlich wie das Proxy-Muster, dient jedoch einem ganz anderen Zweck. Die Delegierung ist ein Abstraktionsmechanismus, der das Verhalten von Objekten (Methoden) zentralisiert.
Allgemein gesprochen: Verwenden Sie die Delegierung als Alternative zur Vererbung. Vererbung ist eine gute Strategie, wenn eine enge Beziehung zwischen übergeordnetem und untergeordnetem Objekt besteht, Vererbung jedoch Objekte sehr eng koppelt. Delegation ist häufig die flexiblere Möglichkeit, eine Beziehung zwischen Klassen auszudrücken.
Dieses Muster wird auch als "Proxy-Ketten" bezeichnet. Einige andere Entwurfsmuster verwenden die Delegierung - die Status-, Strategie- und Besuchermuster hängen davon ab.
quelle
Das Delegationskonzept
Wenn sich in einem übergeordneten Element viele Elemente befinden und Sie Ereignisse für diese Elemente verarbeiten möchten, binden Sie keine Handler an jedes Element. Binden Sie stattdessen den einzelnen Handler an das übergeordnete Element und rufen Sie das untergeordnete Element aus event.target ab. Diese Site bietet nützliche Informationen zum Implementieren der Ereignisdelegierung. http://javascript.info/tutorial/event-delegation
quelle
Bei der Ereignisdelegierung wird ein Ereignis behandelt, das mithilfe eines Ereignishandlers für ein Containerelement sprudelt , das Verhalten des Ereignishandlers jedoch nur aktiviert, wenn das Ereignis für ein Element im Container aufgetreten ist, das einer bestimmten Bedingung entspricht. Dies kann die Behandlung von Ereignissen für Elemente im Container vereinfachen.
Angenommen, Sie möchten einen Klick auf eine Tabellenzelle in einer großen Tabelle ausführen. Sie können eine Schleife schreiben, um einen Klick-Handler an jede Zelle anzuschließen ... oder Sie können einen Klick-Handler an die Tabelle anschließen und die Ereignisdelegierung verwenden, um sie nur für Tabellenzellen (und nicht für Tabellenüberschriften oder das Leerzeichen in a) auszulösen Reihe um Zellen usw.).
Dies ist auch nützlich, wenn Sie Elemente zum Container hinzufügen und daraus entfernen möchten, da Sie sich nicht um das Hinzufügen und Entfernen von Ereignishandlern für diese Elemente kümmern müssen. Haken Sie das Ereignis einfach in den Container ein und behandeln Sie das Ereignis, wenn es sprudelt.
Hier ist ein einfaches Beispiel (es ist absichtlich ausführlich, um eine Inline-Erklärung zu ermöglichen): Behandeln eines Klicks auf ein
td
Element in einer Containertabelle:Bevor wir auf die Details eingehen, möchten wir uns daran erinnern, wie DOM-Ereignisse funktionieren.
DOM-Ereignisse werden vom Dokument an das Zielelement (die Erfassungsphase ) gesendet und dann vom Zielelement zurück zum Dokument (die Blasenphase ) geleitet. Diese Grafik in der alten DOM3-Ereignisspezifikation (jetzt ersetzt, aber die Grafik ist noch gültig) zeigt es wirklich gut:
Nicht alle Ereignisse sprudeln, aber die meisten, einschließlich
click
.Die Kommentare im obigen Codebeispiel beschreiben, wie es funktioniert.
matches
prüft, ob ein Element mit einem CSS-Selektor übereinstimmt, aber Sie können natürlich auch prüfen, ob etwas Ihren Kriterien auf andere Weise entspricht, wenn Sie keinen CSS-Selektor verwenden möchten.Dieser Code wird geschrieben verbosely die einzelnen Schritte zu rufen, sondern auf vage modernen Browsern (und auf IE auch wenn Sie eine polyfill verwenden), können Sie verwenden ,
closest
undcontains
statt der Schleife:Live-Beispiel:
Code-Snippet anzeigen
closest
Überprüft das Element, auf das Sie es aufrufen, um festzustellen, ob es mit dem angegebenen CSS-Selektor übereinstimmt, und gibt in diesem Fall dasselbe Element zurück. Wenn nicht, überprüft es das übergeordnete Element, um festzustellen, ob es übereinstimmt, und gibt das übergeordnete Element zurück, wenn dies der Fall ist. Wenn nicht, überprüft es das übergeordnete Element des Elternteils usw. Es findet also das "nächstgelegene" Element in der Ahnenliste, das dem Selektor entspricht. Da dies möglicherweise über das Containerelement hinausgeht,contains
überprüft der obige Code , ob sich ein passendes Element im Container befindet. Wenn Sie das Ereignis in den Container einbinden, haben Sie angegeben, dass Sie nur Elemente in diesem Container behandeln möchten .Zurück zu unserem Tabellenbeispiel: Wenn Sie eine Tabelle in einer Tabellenzelle haben, stimmt diese nicht mit der Tabellenzelle überein, die die Tabelle enthält:
Code-Snippet anzeigen
quelle
Es ist im Grunde, wie die Assoziation mit dem Element hergestellt wird.
.click
gilt für das aktuelle DOM, während.on
(unter Verwendung der Delegierung) weiterhin für neue Elemente gültig ist, die dem DOM nach der Ereigniszuordnung hinzugefügt wurden.Was besser zu benutzen ist, würde ich sagen, es hängt vom Fall ab.
Beispiel:
.Klickereignis:
Ereignis .on:
Beachten Sie, dass ich den Selektor in der .on getrennt habe. Ich werde erklären warum.
Nehmen wir an, dass wir nach dieser Assoziation Folgendes tun:
Hier werden Sie den Unterschied bemerken.
Wenn das Ereignis über .click verknüpft wurde, folgt Task 5 dem Klickereignis nicht und wird daher nicht entfernt.
Wenn es über .on mit dem separaten Selektor verknüpft wurde, wird es gehorchen.
quelle
Um die Ereignisdelegierung zuerst zu verstehen, müssen wir wissen, warum und wann wir die Ereignisdelegierung tatsächlich benötigen oder wollen.
Es mag viele Fälle geben, aber lassen Sie uns zwei große Anwendungsfälle für die Ereignisdelegation diskutieren. 1. Der erste Fall ist, wenn wir ein Element mit vielen untergeordneten Elementen haben, an denen wir interessiert sind. In diesem Fall fügen wir, anstatt allen diesen untergeordneten Elementen einen Ereignishandler hinzuzufügen, ihn einfach dem übergeordneten Element hinzu und bestimmen dann Auf welches untergeordnete Element wurde das Ereignis ausgelöst?
2. Der zweite Anwendungsfall für die Ereignisdelegierung besteht darin, dass ein Ereignishandler an ein Element angehängt werden soll, das sich beim Laden unserer Seite noch nicht im DOM befindet. Das liegt natürlich daran, dass wir einem Ereignishandler, der nicht auf unserer Seite ist, keinen Ereignishandler hinzufügen können, also im Falle eines Verfalls, den wir codieren.
Angenommen, Sie haben eine Liste mit 0, 10 oder 100 Elementen im DOM, wenn Sie Ihre Seite laden, und weitere Elemente warten in Ihrer Hand darauf, in die Liste aufgenommen zu werden. Es gibt also keine Möglichkeit, einen Ereignishandler für zukünftige Elemente anzuhängen, oder diese Elemente werden noch nicht im DOM hinzugefügt, und es können auch viele Elemente vorhanden sein. Daher wäre es nicht sinnvoll, jeweils einen Ereignishandler anzuhängen von ihnen.
Ereignisdelegation
Also gut, um über Eventdelegation zu sprechen, ist das erste Konzept, über das wir tatsächlich sprechen müssen, das Sprudeln von Events.
Ereignisblasen: Ereignisblasen bedeutet, dass, wenn ein Ereignis für ein DOM-Element ausgelöst oder ausgelöst wird, beispielsweise durch Klicken auf unsere Schaltfläche hier im folgenden Bild, genau dasselbe Ereignis auch für alle übergeordneten Elemente ausgelöst wird.
Das Ereignis wird zuerst auf die Schaltfläche ausgelöst, dann aber auch nacheinander auf alle übergeordneten Elemente, sodass es auch auf den Absatz des Abschnitts des Hauptelements und tatsächlich ganz oben in einem DOM-Baum ausgelöst wird bis zum HTML-Element, das die Wurzel ist. Wir sagen also, dass das Ereignis im DOM-Baum in die Luft sprudelt, und deshalb wird es als Sprudeln bezeichnet.
Zielelement: Das Element, auf das das Ereignis tatsächlich zum ersten Mal ausgelöst wurde, wird als Zielelement bezeichnet. Das Element, das das Ereignis verursacht hat, wird als Zielelement bezeichnet. In unserem obigen Beispiel hier ist es natürlich die Schaltfläche, auf die geklickt wurde. Der wichtige Teil ist, dass dieses Zielelement als Eigenschaft im Ereignisobjekt gespeichert wird. Dies bedeutet, dass alle übergeordneten Elemente, auf die das Ereignis auch ausgelöst wird, das Zielelement des Ereignisses kennen, also wo das Ereignis zuerst ausgelöst wurde.
Das bringt uns zur Ereignisdelegierung, denn wenn das Ereignis im DOM-Baum sprudelt und wir wissen, wo das Ereignis ausgelöst wurde, können wir einfach einen Ereignishandler an ein übergeordnetes Element anhängen und warten, bis das Ereignis sprudelt, und wir können Machen Sie dann alles, was wir mit unserem Zielelement vorhaben. Diese Technik wird als Ereignisdelegation bezeichnet. In diesem Beispiel hier könnten wir einfach den Ereignishandler zum Hauptelement hinzufügen.
Also gut, die Ereignisdelegation besteht darin, den Ereignishandler nicht für das ursprüngliche Element einzurichten, an dem wir interessiert sind, sondern ihn an ein übergeordnetes Element anzuhängen und das Ereignis dort im Grunde zu erfassen, weil es sprudelt. Wir können dann auf das Element einwirken, an dem wir interessiert sind, indem wir die Zielelement-Eigenschaft verwenden.
Beispiel: Nehmen wir nun an, wir haben zwei Listenelemente auf unserer Seite. Nachdem wir Elemente in dieser Liste programmgesteuert hinzugefügt haben, möchten wir ein oder mehrere Elemente aus ihnen löschen. Mit der Technik der Ereignisdelegation können wir unseren Zweck leicht erreichen.
Hinzufügen von Elementen zu dieser Liste:
Elemente löschen:
quelle
Ein Delegat in C # ähnelt einem Funktionszeiger in C oder C ++. Durch die Verwendung eines Delegaten kann der Programmierer einen Verweis auf eine Methode in einem Delegatenobjekt kapseln. Das Delegatenobjekt kann dann an Code übergeben werden, der die referenzierte Methode aufrufen kann, ohne zur Kompilierungszeit wissen zu müssen, welche Methode aufgerufen wird.
Siehe diesen Link -> http://www.akadia.com/services/dotnet_delegates_and_events.html
quelle
Bei der Ereignisdelegierung werden zwei häufig übersehene Funktionen von JavaScript-Ereignissen verwendet: Ereignisblasen und das Zielelement. Wenn ein Ereignis für ein Element ausgelöst wird, z. B. ein Mausklick auf eine Schaltfläche, wird dasselbe Ereignis auch für alle Vorfahren dieses Elements ausgelöst . Dieser Vorgang wird als Ereignisblasen bezeichnet. Das Ereignis sprudelt vom Ursprungselement zum oberen Rand des DOM-Baums.
Stellen Sie sich eine HTML-Tabelle mit 10 Spalten und 100 Zeilen vor, in der etwas passieren soll, wenn der Benutzer auf eine Tabellenzelle klickt. Zum Beispiel musste ich einmal jede Zelle einer Tabelle dieser Größe beim Klicken bearbeitbar machen. Das Hinzufügen von Ereignishandlern zu jeder der 1000 Zellen wäre ein großes Leistungsproblem und möglicherweise eine Ursache für Speicherverluste beim Absturz des Browsers. Stattdessen würden Sie mithilfe der Ereignisdelegierung nur einen Ereignishandler zum Tabellenelement hinzufügen, das Klickereignis abfangen und bestimmen, auf welche Zelle geklickt wurde.
quelle
Hängen Sie einen Ereignis-Listener an ein übergeordnetes Element an, das ausgelöst wird, wenn ein Ereignis für ein untergeordnetes Element auftritt.
EreignisausbreitungWenn ein Ereignis durch das DOM vom untergeordneten zum übergeordneten Element verschoben wird, wird dies als Ereignisausbreitung bezeichnet , da sich das Ereignis ausbreitet oder durch das DOM bewegt.
In diesem Beispiel wird ein Ereignis (onclick) von einer Schaltfläche an den übergeordneten Absatz übergeben.
Codepen
quelle