2013-01-05 7 views
5

Desidero utilizzare i listener di eventi per impedire la generazione di eventi su un div all'interno di un div con funzioni onclick. Questo funziona, il passaggio di parametri come ho previsto:Javascript multiplo dinamico addEventListener creato per parametri di passaggio del loop non funzionanti

<div onclick="doMouseClick(0, 'Dog', 'Cat');" id="button_id_0"></div> 
<div onclick="doMouseClick(1, 'Dog', 'Cat');" id="button_id_1"></div> 
<div onclick="doMouseClick(2, 'Dog', 'Cat');" id="button_id_2"></div> 

<script> 
function doMouseClick(peram1, peram2, peram3){ 
    alert("doMouseClick() called AND peram1 = "+peram1+" AND peram2 = "+peram2+" AND peram3 = "+peram3); 
} 
</script> 

Tuttavia, ho cercato di creare più listener di eventi in un ciclo con questo:

<div id="button_id_0"></div> 
<div id="button_id_1"></div> 
<div id="button_id_2"></div> 

<script> 
function doMouseClick(peram1, peram2, peram3){ 
    alert("doMouseClick() called AND peram1 = "+peram1+" AND peram2 = "+peram2+" AND peram3 = "+peram3); 
} 

var names = ['button_id_0', 'button_id_1', 'button_id_2']; 

    for (var i=0; i<names.length; i++){ 

     document.getElementById(names[i]).addEventListener("click", function(){ 
     doMouseClick(i, "Dog", "Cat"); 

    },false); 

} 

</script> 

Si assegna correttamente la funzione di click per ogni div, ma la il primo parametro per ciascuno, peram1, è 3. Mi aspettavo 3 diversi gestori di eventi che passassero diversi valori di i per peram1.

Perché sta succedendo? I gestori di eventi non sono tutti separati?

risposta

19

problema è chiusure, poiché JS non ha blocchi portata (solo funzione di portata) i non è quello che pensi perché la funzione di evento crea un altro ambito quindi per il momento si utilizza i E 'già l'ultimo valore il ciclo for. È necessario mantenere il valore di i.

Utilizzando un IIFE:

for (var i=0; i<names.length; i++) { 
    (function(i) { 
    // use i here 
    }(i)); 
} 

Uso forEach:

names.forEach(function(v,i) { 
    // i can be used anywhere in this scope 
}); 
+0

Grazie mille:)! – KDawg

+0

Grazie. Mi chiedevo perché 'i' non rientravano nel perimetro e restituivano un elemento' indefinito'. –

1

Tutto è globale in javascript. Chiama la variabile i che è impostata su 3 dopo il ciclo ... se si imposta i su 1000 dopo il ciclo, allora si vedrebbe ogni chiamata di metodo produrre 1000 per i.

Se si desidera mantenere lo stato, è necessario utilizzare gli oggetti. Chiedi all'oggetto di avere un metodo di callback che assegni al metodo click.

Hai detto di fare questo per l'evento bubbling ... per fermare l'evento bublling, non hai davvero bisogno di questo, dato che è incorporato nella lingua. Se si desidera impedire il bubbling degli eventi, è necessario utilizzare il metodo stopPropagation() dell'oggetto event passato alla richiamata.

function doStuff(event) { 
    //Do things 
    //stop bubbling 
    event.stopPropagation(); 
} 
+0

Grazie per avermi aiutato con lo stopPropogation(), come pure - E 'risolto l'altra parte del mio problema L'eventlistener mi ha lasciato con lo stesso borbido problema che mi hai suggerito - che stavo cercando di risolvere - ma questa risposta qui, ha risolto anche il mio problema di bolle. Grazie ancora:) Uomo! questo Stackoverflow è un gruppo utile di persone! – KDawg

+0

I tuoi commenti su "se si imposta i a 1000 dopo il ciclo, allora si vedrebbe ogni chiamata di metodo produrre 1000 per i" erano anche completamente accurati:) – KDawg

3

Come già indicate il problema è quello di fare con chiusure e portata variabile. Un modo per assicurarsi che il valore corretto venga passato è scrivere un'altra funzione che restituisca la funzione desiderata, tenendo le variabili all'interno dello scope corretto. jsfiddle

var names = ['button_id_0', 'button_id_1', 'button_id_2']; 

function getClickFunction(a, b, c) { 
    return function() { 
    doMouseClick(a, b, c) 
    } 
} 
for (var i = 0; i < names.length; i++) { 
    document.getElementById(names[i]).addEventListener("click", getClickFunction(i, "Dog", "Cat"), false); 
} 

E per illustrare un modo si potrebbe fare questo con un oggetto, invece:

var names = ['button_id_0', 'button_id_1', 'button_id_2']; 

function Button(id, number) { 
    var self = this; 
    this.number = number; 
    this.element = document.getElementById(id); 
    this.click = function() { 
    alert('My number is ' + self.number); 
    } 
    this.element.addEventListener('click', this.click, false); 
} 
for (var i = 0; i < names.length; i++) { 
    new Button(names[i], i); 
} 

o in modo leggermente diverso:

function Button(id, number) { 
    var element = document.getElementById(id); 
    function click() { 
    alert('My number is ' + number); 
    } 
    element.addEventListener('click', click, false); 
} 
for (var i = 0; i < names.length; i++) { 
    new Button(names[i], i); 
} 
+0

Questo è stato molto utile grazie. Un po 'avanzato per me dato che ho appena iniziato ad usare gli ascoltatori di eventi in javascript - lo studierò ulteriormente. – KDawg

-1

E 'a causa di chiusure.

Check this out: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures#Creating_closures_in_loops_A_common_mistake

Il codice di esempio e il codice è essenzialmente la stessa, è un errore comune per coloro che non so "chiusura".

Per semplificare, quando si crea una funzione di gestore, non solo accede alla variabile i dall'ambiente esterno, ma anche "ricorda" i.

Così, quando il gestore viene chiamato, verrà utilizzata la i ma la variabile i è ora, dopo il ciclo for, 2.

+1

I collegamenti a risorse esterne sono incoraggiati, ma per favore aggiungi un contesto intorno al link in modo che i tuoi colleghi possano avere un'idea di cosa sia e perché è lì. Citare sempre la parte più rilevante di un link importante, nel caso in cui il sito target non sia raggiungibile o sia permanentemente offline. Da [Come rispondere] (http://stackoverflow.com/help/how-to-answer). –

+0

@MoralesBatovski Grazie per il tuo promemoria. Ho appena modificato il mio post. – olindk

Problemi correlati