Pregunta

El objetivo

Quiero asignar dinámicamente controladores de eventos a algunos divs en páginas a lo largo de un sitio.

Mi método

Estoy usando jQuery para enlazar funciones anónimas como controladores para eventos div seleccionados.

El problema

El código itera una matriz de nombres de div y urls asociadas. El nombre de div se utiliza para establecer el destino de enlace, es decir, adjuntar este controlador de eventos a este evento de div.

Mientras que los controladores de eventos están vinculados con éxito a cada uno de los eventos div, las acciones desencadenadas por esos controladores de eventos solo apuntan al último elemento de la matriz.

Entonces, la idea es que si el usuario se mueve sobre un div determinado, debería ejecutar una animación deslizable para ese div. Pero en lugar de eso, pasar el ratón sobre div1 (rangeTabAll) activa una animación deslizable para div4 (rangeTabThm). Lo mismo es cierto para los divs 2, 3, etc. El orden no es importante. Cambie los elementos de la matriz y los eventos siempre apuntarán al último elemento de la matriz, div4.

Mi código - (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);} );
            }
        }

Mi teoría

O bien no veo un error de sintaxis cegadoramente obvio o es un problema de transferencia por referencia. Inicialmente tuve la siguiente declaración para establecer el valor de curTab:

curTab=inlineRangeNavUrls[i][0];

Entonces, cuando se produjo el problema, pensé que al cambiar (a través de iteración de bucle) la referencia a curTab, en realidad estaba cambiando la referencia de todos los controladores de eventos de funciones anónimas anteriores al nuevo curTab valor también ... por lo que los controladores de eventos siempre apuntaron a la última división.

Entonces, lo que realmente necesitaba hacer era pasar el valor curTab a los controladores de eventos de la función anónima, no la referencia curTab objeto .

Así que pensé:

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

solucionaría el problema, pero no lo hace. El mismo trato. Claramente me falta algo de conocimiento clave, y probablemente muy básico, sobre el problema. Gracias.

¿Fue útil?

Solución

Necesitas crear una nueva variable en cada paso a través del bucle, para que se capture en los cierres que estás creando para los controladores de eventos.

Sin embargo, el simple hecho de mover la declaración de la variable al bucle no lo logrará, porque JavaScript no introduce un nuevo alcance para bloques arbitrarios .

Una forma fácil de forzar la introducción de un nuevo ámbito es usar otra función anónima:

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 sugiere , en realidad puedes limpiar esto bastante usando jQuery hover () función:

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]); 
}

Otros consejos

lo que está sucediendo aquí es que sus funciones anónimas están formando un cierre y llevándose su alcance externo con ellas. Eso significa que cuando hace referencia a curTab dentro de su función anómala, cuando el controlador de eventos ejecuta esa función, buscará el valor actual de curTab en su ámbito externo. Eso será lo que hayas asignado por última vez a curTab. (no lo que se asignó en el momento en que vinculó la función)

lo que debes hacer es cambiar esto:

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

a esto:

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

esto copiará el valor de curTab en el alcance de la función externa, que la función interna llevará consigo. Esta copia ocurre al mismo tiempo que vincula la función interna al controlador de eventos, por lo que " mylocalvariable " refleja el valor de curTab en ese momento. Luego, la próxima vez alrededor del bucle, se creará una nueva función externa, con un nuevo alcance, y el siguiente valor de curTab se copiará en él.

La respuesta de

shog9 logra básicamente lo mismo, pero su código es un poco más austero.

es un poco complicado, pero tiene sentido si lo piensas. Los cierres son raros.

edit: oops, olvidaste devolver la función interna. Corregido.

Creo que estás haciendo esto más complicado de lo que debería ser. Si todo lo que está haciendo es asignar un efecto deslizante en mouseover / out, intente hover efecto con jquery.

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

Si publicaste tu HTML completo, te podría decir exactamente cómo hacerlo :)

Puedes poner el valor de tu variable en una etiqueta no existente, y luego puedes leerla desde allí. Este fragmento es parte de un cuerpo de bucle:

 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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top