addEventListener usando per i valori di loop e passaggio

Sto cercando di aggiungere listener di eventi a più oggetti utilizzando un ciclo for, ma alla fine tutti gli ascoltatori hanno come target lo stesso object -> l’ultimo.

Se aggiungo manualmente gli ascoltatori definendo boxa e boxb per ogni istanza, funziona. Immagino che sia l’addEvent for-loop che non funziona come speravo. Forse uso l’approccio sbagliato del tutto.

Esempio usando 4 del class = “contenitore” Trigger sul contenitore 4 funziona come dovrebbe. Attivare l’evento di trigger contenitore 1,2,3 sul contenitore 4, ma solo se il trigger è già stato triggersto.

Funzione da eseguire al clic:

function makeItHappen(elem, elem2){ var el = document.getElementById(elem); el.style.transform = "flip it"; var el2 = document.getElementById(elem2); el2.style.transform = "flip it"; } 

Funzione di caricamento automatico per aggiungere gli ascoltatori:

 function addEvents(){ var elem = document.getElementsByClassName("triggerClass"); for(var i=0; i < elem.length; i+=2){ var k = i + 1; var boxa = elem[i].parentNode.id; var boxb = elem[k].parentNode.id; elem[i].addEventListener("click", function(){makeItHappen(boxa,boxb);}, false); elem[k].addEventListener("click", function(){makeItHappen(boxb,boxa);}, false); } } 

Codice HTML

 

some text

some text

some text

some text

Chiusure! : D

Questo codice fisso funziona come previsto:

 for (var i = 0; i < elem.length; i += 2) { (function () { var k = i + 1; var boxa = elem[i].parentNode.id; var boxb = elem[k].parentNode.id; elem[i].addEventListener("click", function() { makeItHappen(boxa,boxb); }, false); elem[k].addEventListener("click", function() { makeItHappen(boxb,boxa); }, false); }()); // immediate invocation } 

Perché questo lo risolve?

 for(var i=0; i < elem.length; i+=2){ var k = i + 1; var boxa = elem[i].parentNode.id; var boxb = elem[k].parentNode.id; elem[i].addEventListener("click", function(){makeItHappen(boxa,boxb);}, false); elem[k].addEventListener("click", function(){makeItHappen(boxb,boxa);}, false); } 

È in realtà non-strict JavaScript. È interpretato in questo modo:

 var i, k, boxa, boxb; for(i=0; i < elem.length; i+=2){ k = i + 1; boxa = elem[i].parentNode.id; boxb = elem[k].parentNode.id; elem[i].addEventListener("click", function(){makeItHappen(boxa,boxb);}, false); elem[k].addEventListener("click", function(){makeItHappen(boxb,boxa);}, false); } 

A causa del sollevamento variabile , le dichiarazioni var vengono spostate nella parte superiore dell'ambito. Poiché JavaScript non ha scope di blocco ( for , if , while ecc.) Vengono spostate all'inizio della funzione. Aggiornamento: a partire da ES6 è ansible utilizzare let per ottenere variabili con scope a blocchi.

Quando viene eseguito il codice, accade quanto segue: nel ciclo for si aggiungono i richiami di clic e si assegna boxa , ma il suo valore viene sovrascritto nella successiva iterazione. Quando viene boxa l'evento click, viene eseguito il callback e il valore di boxa è sempre l'ultimo elemento nell'elenco.

Usando una chiusura (chiudendo i valori di boxa , boxa , ecc.) Si associa il valore all'ambito del gestore di clic.


Gli strumenti di analisi del codice come JSLint o JSHint saranno in grado di catturare codice sospetto come questo. Se stai scrivendo molto codice, vale la pena dedicare del tempo a imparare come utilizzare questi strumenti. Alcuni IDE li hanno integrati.

function(){makeItHappen(boxa,boxb);} problema scope / closure come function(){makeItHappen(boxa,boxb);} riferimenti boxa e boxb sono quindi sempre gli ultimi elementi.

Per risolvere il problema:

 function makeItHappenDelegate(a, b) { return function(){ makeItHappen(a, b) } } // ... elem[i].addEventListener("click", makeItHappenDelegate(boxa,boxb), false); 

Puoi utilizzare Function Binding. Non hai bisogno di usare chiusure. Vedi sotto:

Prima :

 function addEvents(){ var elem = document.getElementsByClassName("triggerClass"); for(var i=0; i < elem.length; i+=2){ var k = i + 1; var boxa = elem[i].parentNode.id; var boxb = elem[k].parentNode.id; elem[i].addEventListener("click", function(){makeItHappen(boxa,boxb);}, false); elem[k].addEventListener("click", function(){makeItHappen(boxb,boxa);}, false); } } 

Dopo :

 function addEvents(){ var elem = document.getElementsByClassName("triggerClass"); for(var i=0; i < elem.length; i+=2){ var k = i + 1; var boxa = elem[i].parentNode.id; var boxb = elem[k].parentNode.id; elem[i].addEventListener("click", makeItHappen.bind(this, boxa, boxb), false); elem[k].addEventListener("click", makeItHappen.bind(this, boxa, boxb), false); } } 

È a causa delle chiusure.

Controlla questo: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures#Creating_closures_in_loops_A_common_mistake

Il codice di esempio e il codice sono essenzialmente gli stessi, è un errore comune per coloro che non conoscono la “chiusura”.

Per dirla in modo semplice, quando crei una funzione di gestore all’interno di addEvents() , non accede solo alla variabile i dall’ambiente di addEvents() , ma anche “ricorda” i .

E poiché il tuo gestore “ricorda” i , la variabile non scomparirà dopo l’esecuzione di addEvents() .

Quindi, quando viene chiamato il gestore, utilizzerà la i ma la variabile i è ora, dopo il ciclo for, 3.

Ho anche avuto questo problema qualche tempo fa. L’ho risolto utilizzando una funzione “aggiungi” al di fuori del ciclo, per assegnare eventi e ha funzionato perfettamente.

La tua sceneggiatura dovrebbe assomigliare.

 function addEvents(){ var elem = document.getElementsByClassName("triggerClass"); for(var i=0; i < elem.length; i+=2){ var k = i + 1; var boxa = elem[i].parentNode.id; var boxb = elem[k].parentNode.id; //- edit ---------------------------| adds(boxa, boxb); } } //- adds function ----| function adds(obj1, obj2){ obj1.addEventListener("click", function(){makeItHappen(obj1, obj2);}, false); obj2.addEventListener("click", function(){makeItHappen(obj1, obj2);}, false); } //- end edit -----------------------| function makeItHappen(elem, elem2){ var el = document.getElementById(elem); el.style.transform = "flip it"; var el2 = document.getElementById(elem2); el2.style.transform = "flip it"; }