webentwicklung-frage-antwort-db.com.de

hinzufügen von "Klick" -Ereignis-Listenern in einer Schleife

Refactoring des Standards onClick innerhalb des HTML-Tags für Listener, bei denen ein Problem mit meinem Code aufgetreten ist:

var td;
    for (var t=1;t<8;t++){
        td = document.getElementById('td'+t);
        if (typeof window.addEventListener==='function'){
                td.addEventListener('click',function(){
                    console.log(td);
            })}
 }  

Wenn das td-Element angeklickt wird, wird davon ausgegangen, dass auf td mit dem letzten Index aus der Schleife geklickt wurde, z. 7
Sieht aus, als wäre eventListeners nur für das letzte Element in dieser Schleife aufgefüllt worden.
Die Loop-Initialisierung sieht korrekt aus.
.__ Warum ist das passiert?

Hier ist Live-Code

20
sergionni

Sie müssen die Zuweisung des Ereignis-Listeners wie folgt abschließen:

var td;
for (var t = 1; t < 8; t++){
    td = document.getElementById('td'+t);
    if (typeof window.addEventListener === 'function'){
        (function (_td) {
            td.addEventListener('click', function(){
                console.log(_td);
            });
        })(td);
    }
}
57
jabclab

Was ist los

Die Variable td wird außerhalb Ihrer Event-Handler definiert. Wenn Sie auf eine Zelle klicken, protokollieren Sie den letzten Wert, auf den sie festgelegt wurde.

Technisch gesehen: Jede Event-Handler-Funktion ist eine Schließung - eine Funktion, die auf Variablen aus einem äußeren Bereich verweist.

Die allgemeine Lösung

Die allgemeine Lösung für diese Art von Problem besteht darin, den Ereignishandler von einer Wrapper-Funktion zurückzugeben, wobei die zu überwachenden Variablen als Argumente übergeben werden:

td.addEventListener('click', function(wrapTD) {
    return function() { console.log(wrapTD); }
}(td));

Die Argumente sind jetzt an den Bereich der aufgerufenen Wrapper-Funktion gebunden.

Einfachere Lösung: Verwenden Sie this

Es gibt jedoch eine noch einfachere Option. In einem Event-Handler wirdthis auf das Element gesetzt, für das der Handler definiert ist , sodass Sie statt this einfach td verwenden können:

td.addEventListener('click', function() {
    console.log(this);
});

Noch einfacher: keine Schleife!

Schließlich können Sie Sie können die for-Schleife vollständig loswerden und einen einzelnen Event-Handler für die gesamte Tabelle festlegen:

var table = document.getElementById('my-table');

table.addEventListener('click', function(e) {
    if (e.target.nodeName.toUpperCase() !== "TD") return;

    var td = e.target;
    console.log(td);
});

Dies ist eine viel bessere Lösung für größere Tabellen, da Sie mehrere Ereignishandler durch nur einen ersetzen. Wenn Sie Ihren Text in ein anderes Element einschließen, müssen Sie dies anpassen, um zu prüfen, ob das Zielelement ein Nachkomme einer td ist.

31
Jordan Gray

Was hier passiert, ist, dass Sie die Variable 'td' im Gültigkeitsbereich der Ereignis-Listener-Funktion behalten. Es gibt nur eine Instanz von 'td', die jedes Mal aktualisiert wird, wenn die for-Schleife wiederholt wird. Wenn die for-Schleife beendet ist, wird der Wert von td nun auf das Element '# td7' gesetzt, und Ihr Event-Handler protokolliert einfach den aktuellen Wert von td.

In dem obigen Beispiel können Sie einfach "das Folgende" protokollieren:

var td;
for (var t=1;t<8;t++){
    td = document.getElementById('td'+t);
    if (typeof window.addEventListener==='function'){
      td.addEventListener('click',function(){
        console.log(this);
      });
    }
}

da 'this' auf das Element gesetzt ist, an das ein Ereignis für die Ausführung eines Ereignishandlers gebunden war.

Ich schätze, Sie suchen nach einer Antwort darauf, wie Sie den Iterator festhalten, wenn Sie Closures innerhalb einer for-Schleife erstellen. Dazu möchten Sie eine Funktion außerhalb der for-Schleife definieren.

for (var t=1;t<8;t++){
  bind_event(t);
}

function bind_event(t) {
    var td = document.getElementById('td'+t);
    if (typeof window.addEventListener==='function'){
      td.addEventListener('click',function(){
        console.log(td);
      });
    }
}

Auf diese Weise wird bei jeder Ausführung von bind_event eine Instanz einer Variablen mit dem Namen 'td' erstellt, und diese Instanz wird für die Ereignislistenerfunktion geschlossen. Es ist erwähnenswert, dass 't' in bind_event auch eine neue Variable ist.

7
Will Tomlins

Wie ich es verstehe, geschieht dies aufgrund der Schließung ... Sie weisen Event Handler im Rahmen der FOR-Anweisung zu. Wenn ein Klick erfolgt, wird die letzte Version von TD im Geltungsbereich von FOR benötigt und in das Protokoll geschrieben. 

1
Alex Dn

folgendes sollte wie erwartet funktionieren:

  for (var t=1;t<8;t++){
        var td;
        td = document.getElementById('td'+t);
        if (typeof window.addEventListener==='function'){
                td.addEventListener('click',function(){
                    console.log(this);
            })}
 } 
0
Evert