16

L'ObiettivoCome passare una variabile in base al valore a una funzione javascript anonima?

voglio assegnare dinamicamente i gestori di eventi ad alcuni div alle pagine in tutto un sito.

mio Metodo

Im utilizzando jQuery per legare funzioni anonime come gestori per gli eventi selezionati div.

Il problema

Il codice itera un array di nomi div e URL associati. Il nome div viene utilizzato per impostare l'obiettivo di associazione, ad esempio, collegare questo gestore di eventi a questo evento div.

Mentre i gestori di eventi sono associati correttamente a ciascuno degli eventi div, le azioni attivate da tali gestori eventi hanno sempre come target solo l'ultimo elemento dell'array.

Quindi l'idea è che se l'utente esegue il mouse su un div specificato, dovrebbe eseguire un'animazione slide-out per quel div. Invece, mousing su div1 (rangeTabAll) attiva un'animazione slide-out per div4 (rangeTabThm). Lo stesso vale per i div 2, 3, ecc. L'ordine non è importante. Cambiare gli elementi dell'array attorno e gli eventi avranno sempre come target l'ultimo elemento dell'array, div4.

My Code - (usa jQuery)

var curTab, curDiv; 
var inlineRangeNavUrls=[['rangeTabAll','range_all.html'],['rangeTabRem','range_remedial.html'], 
       ['rangeTabGym','range_gym.html'],['rangeTabThm','range_thermal.html']]; 
     for (var i=0;i<inlineRangeNavUrls.length;i++) 
     { 
      curTab=(inlineRangeNavUrls[i][0]).toString(); 
      curDiv='#' + curTab; 
      if ($(curDiv).length) 
      { 
       $(curDiv).bind("mouseover", function(){showHideRangeSlidingTabs(curTab, true);}); 
       $(curDiv).bind("mouseout", function(){showHideRangeSlidingTabs(curTab, false);}); 
      } 
     } 

mia teoria

sto o non vedendo un errore di sintassi assolutamente ovvio o la sua un passaggio dal problema di riferimento. Inizialmente ho avuto la seguente dichiarazione per impostare il valore di curTab:

curTab=inlineRangeNavUrls[i][0]; 

Così, quando il problema si è verificato Ho pensato che come ho cambiato (via per iterazione del ciclo) il riferimento alla curTab, ero infatti cambiare il riferimento per tutti i precedenti gestori di eventi di funzioni anonimi al nuovo valore di curTab .... ed è per questo che i gestori di eventi hanno sempre preso di mira l'ultimo div.

Così che cosa ho davvero bisogno di fare era passare il valore curTab ai gestori di eventi funzione anonima non il curTab oggetto di riferimento.

Così ho pensato:

curTab=(inlineRangeNavUrls[i][0]).toString(); 

sarebbe risolvere il problema, ma non è così. Stesso affare. Quindi chiaramente mi mancano alcune conoscenze chiave e probabilmente molto basilari riguardo al problema. Grazie.

+0

JavaScript passa sempre e assegna per valore. La tua domanda non riguarda affatto il passaggio; ma piuttosto con la cattura di variabili da chiusure. – newacct

risposta

20

È necessario creare una nuova variabile su ogni passaggio attraverso il ciclo, in modo che potrai ottenere catturato in le chiusure che stai creando per i gestori di eventi.

Tuttavia, il semplice spostamento della dichiarazione della variabile nel ciclo non compirà questo, perché JavaScript doesn't introduce a new scope for arbitrary blocks.

Un modo semplice per forzare l'introduzione di un nuovo ambito è quello di utilizzare un'altra funzione anonima:

for (var i=0;i<inlineRangeNavUrls.length;i++) 
{ 
    curDiv='#' + inlineRangeNavUrls[i][1]; 
    if ($(curDiv).length) 
    { 
    (function(curTab) 
    { 
     $(curDiv).bind("mouseover", function(){showHideRangeSlidingTabs(curTab, true);}); 
     $(curDiv).bind("mouseout", function(){showHideRangeSlidingTabs(curTab, false);}); 
    })(inlineRangeNavUrls[i][0]); // pass as argument to anonymous function - this will introduce a new scope 
    } 
} 

As Jason suggests, si può effettivamente pulire questo un po 'utilizzando jQuery built-in hover() funzione:

for (var i=0;i<inlineRangeNavUrls.length;i++) 
{ 
    (function(curTab) // introduce a new scope 
    { 
    $('#' + inlineRangeNavUrls[i][1]) 
    .hover(
     function(){showHideRangeSlidingTabs(curTab, true);}, 
     function(){showHideRangeSlidingTabs(curTab, false);} 
    ); 
    // establish per-loop variable by passsing as argument to anonymous function 
    })(inlineRangeNavUrls[i][0]); 
} 
+0

Grandi cose, grazie. – rism

1

Penso che lo stai rendendo più complicato di quanto dovrebbe essere. Se tutto ciò che stai facendo è assegnare un effetto scorrevole al mouseover/out, prova l'effetto hover con jquery.

$("#mytab").hover(function(){ 
    $(this).next("div").slideDown("fast");}, 
    function(){ 
    $(this).next("div").slideUp("fast"); 
}); 

Se avete inviato la vostra piena HTML Potrei dirti esattamente come farlo :)

+2

true, ma questo non è ciò che sta causando il problema. –

+0

... quindi ottengo un downvote? per fornire una risposta più semplice e più chiara al problema dell'OP? veramente? – Jason

+0

La tua risposta non risolve il problema dell'OP. – Breton

15

quello che sta succedendo qui è che le tue funzioni anonime stanno formando una chiusura, e prendendo il loro ambito esterno con loro. Ciò significa che quando fai riferimento a curTab all'interno della tua funzione anomala, quando il gestore di eventi esegue quella funzione, sta andando a cercare il valore corrente di curTab corrente nel tuo ambito esterno. Quello sarà l'ultimo che hai assegnato a curTab. (Non quello che è stato assegnato al momento binded la funzione)

ciò che devi fare è cambiare questo:

$(curDiv).bind("mouseover", function(){showHideRangeSlidingTabs(curTab, true);}); 

a questo:

$(curDiv).bind("mouseover", 
    (function (mylocalvariable) { 
     return function(){ 
      showHideRangeSlidingTabs(mylocalvariable, true); 
     } 
    })(curTab) 
); 

questo copierà il valore di curTab nell'ambito della funzione esterna, che la funzione interna prenderà con sé. Questa copia avviene nello stesso momento in cui si sta vincolando la funzione interna al gestore eventi, quindi "mylocalvariable" riflette il valore di curTab in quel momento. Quindi, la prossima volta intorno al ciclo, verrà creata una nuova funzione esterna, con un nuovo ambito, e verrà copiato il valore successivo di curTab.

La risposta di shog9 realizza sostanzialmente la stessa cosa, ma il suo codice è un po 'più austero.

è un po 'complicato, ma ha senso se ci pensate. Le chiusure sono strane.

modifica: oops, ha dimenticato di restituire la funzione interna. Fisso.

+0

Grazie mille, un po 'di lancio della moneta per una risposta accettata. – rism

1

È possibile inserire il valore della variabile in un tag non esistente e successivamente leggerlo da lì. Questo snippet fa parte di un corpo del ciclo:

s = introduction.introductions[page * 6 + i][0]; //The variables content 
$('#intro_img_'+i).attr('tag' , s);    //Store them in a tag named tag 
$('#intro_img_'+i).click(function() {introduction.selectTemplate(this, $(this).attr('tag'));} ); //retrieve the stored data 
+0

per essere compatibile con HTML5 è possibile aggiungere 'data-' prima di 'tag' per rendere' data-tag', quindi è possibile utilizzare il metodo ['dati'] di jQuery (http://api.jquery.com/data/). – Brombomb

Problemi correlati