Domanda

L'obiettivo

Voglio assegnare dinamicamente i gestori di eventi ad alcuni div nelle pagine di un sito.

Il mio metodo

Sto usando jQuery per associare funzioni anonime come gestori per eventi div selezionati.

Il problema

Il codice scorre una matrice di nomi div e URL associati. Il nome div viene utilizzato per impostare l'obiettivo di associazione, ad esempio associare questo gestore eventi a questo evento div.

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

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

Il mio codice - (utilizza 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);} );
            }
        }

La mia teoria

Non vedo un errore di sintassi accecante o è un problema di passaggio per riferimento. Inizialmente avevo la seguente dichiarazione per impostare il valore di curTab:

curTab=inlineRangeNavUrls[i][0];

Quindi, quando si è verificato il problema, ho capito che mentre cambiavo (tramite per iterazione in loop) il riferimento a curTab, in effetti stavo cambiando il riferimento per tutti i precedenti gestori di eventi con funzione anonima al nuovo curTab valore anche .... motivo per cui i gestori di eventi hanno sempre preso di mira l'ultimo div.

Quindi quello che dovevo davvero fare era passare il valore di curTab ai gestori di eventi di funzione anonima, non il riferimento oggetto di curTab.

Quindi ho pensato:

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

risolverebbe il problema, ma non lo fa. Lo stesso affare. Quindi chiaramente mi manca qualche conoscenza chiave, e probabilmente molto basilare, riguardo al problema. Grazie.

È stato utile?

Soluzione

Devi creare una nuova variabile ad ogni passaggio del ciclo, in modo che venga catturata nelle chiusure che stai creando per i gestori di eventi.

Tuttavia, il semplice spostamento della dichiarazione della variabile nel ciclo non compirà ciò, poiché JavaScript non introduce un nuovo ambito per i blocchi arbitrari .

Un modo semplice per forzare l'introduzione di un nuovo ambito è usare 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 suggerisce , puoi effettivamente ripulirlo un po 'usando di jQuery 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]); 
}

Altri suggerimenti

quello che sta succedendo qui è che le tue funzioni anonimiche stanno chiudendo e portando con sé il loro scopo esteriore. Ciò significa che quando fai riferimento a curTab all'interno della tua funzione anomala, quando il gestore di eventi esegue quella funzione, cercherà il valore corrente di curTab nel tuo ambito esterno. Sarà quello che hai assegnato l'ultima volta a curTab. (non quello che è stato assegnato al momento in cui hai associato la funzione)

quello 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 porterà con sé. Questa copia avviene contemporaneamente che stai vincolando la funzione interna al gestore eventi, quindi "mylocalvariable" riflette il valore di curTab in quel momento. Quindi la prossima volta intorno al loop, verrà creata una nuova funzione esterna, con un nuovo ambito, e il valore successivo di curTab verrà copiato in esso.

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 pensi. Le chiusure sono strane.

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

Penso che tu lo stia rendendo più complicato di quanto debba essere. Se tutto ciò che stai facendo è assegnare un effetto scorrevole al passaggio del mouse / fuori, prova hover effetto con jquery.

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

Se hai pubblicato il tuo codice HTML completo, posso dirti esattamente come farlo :)

Puoi inserire il valore della tua variabile in un tag inesistente e in seguito puoi leggerli da lì. Questo frammento 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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top