2012-08-23 33 views
9

Estoy obteniendo resultados inesperados con jQuery tratando de establecer el método "clic" de un div. Por favor, consulte this jsfiddle. Asegúrese de abrir la ventana de la consola. Haga clic en la palabra varias veces y vea la salida de la consola. La función de clic se llama varias veces cuando solo se debe llamar una vez.jquery .click llamado varias veces

El código comentado al final funciona bien. ¿Estoy haciendo algo mal? Soy nuevo en jQuery.

Aquí está el código:

function toggleDiv(status) 
{ 
    console.log("toggleDiv(" + status + ")"); 
    if (status) { 
     $("#test").html("Goodbye"); 
    } 
    else { 
     $("#test").html("Hello"); 
    } 
    $("#test").click(function() { 
     toggleDiv(!status); 
    }); 

    // Non-jquery method works fine.... 
    //document.getElementById("test").onclick = function() { 
    // toggleDiv(!status); 
    //} 
}​ 

Actualización: Parece que hay un montón de maneras de pelar este gato. El verdadero problema aquí fue que no comprendí que las funciones de "clic" de jQuery ADMITEN otro controlador. Pensé que REEMPLAZÓ el controlador actual.

Respuesta

17

Usted está configurando un nuevo .click() eventHandler cada vez que se guarda clic en él (que a su vez crea aún más eventos). En una nota lateral, intente nunca usar los eventos onclick/onmouseover/onmouseout/etc en elementos DOM. En Internet Explorer estos crean bloques de script (que se puede ver de forma visible si se utiliza Visual Studio páginas con miles de estos rendimiento desaceleración tremendamente

Parece que está tratando de lograr esto:.!

jsFiddle DEMO

$("#test").on('click', function() { 
    var this$ = $(this), 
     _status = !!this$.data('status'); // force to boolean 
        // ^will default to false since we have no data-status attribute yet 

    this$.html(_status ? 'Hello' : 'Goodbye') 
     .data('status', !_status); 
});​ 
+0

Gracias. No estoy familiarizado con el atributo "estado de datos", pero se ajusta a mis necesidades. Sin embargo, tenga en cuenta que para que su código funcione como alternar, necesita agregar "$ (this) .data ('status', true);" a otra declaración. –

+0

Si solo desea cambiar ese texto, debe echar un vistazo a mi respuesta. No necesita usar .data() en absoluto – kannix

+0

¿Por qué mezcla $ ("# test") y $ (esto)? – kannix

13

que estés volver a registrar el manejador click una y otra vez de forma recursiva.

Una solución correcta (de las muchas variaciones posibles) es la siguiente:

$(function() { 
    var status = false; 

    $('#test').click(function() { 
     status = !status; 
     $(this).html(status ? 'Goodbye' : 'Hello'); 
    }); 
}); 

y luego tiene que quitar el atributo onclick del HTML - no es bueno mezclar DOM0 y eventos DOM3 manipulación.

Ver http://jsfiddle.net/alnitak/8aBxp/

+0

+1 por golpearme también, entonces lol :) –

+0

Gracias. Esto también funciona, pero creo que la respuesta de mcpDESIGNS se ajusta mejor a mis necesidades. –

3

lo más probable es que está ejecutando toggleDiv veces mutliple, lo que resulta en el evento click estar ligado en múltiples ocasiones. enlazar el evento click fuera de la función toggleDiv.

var status = false; 
function toggleDiv() 
{ 
    console.log("toggleDiv(" + status + ")"); 
    if (status) { 
     $("#test").html("Goodbye"); 
    } 
    else { 
     $("#test").html("Hello"); 
    } 
    status = !status; 
}​ 
$("#test").click(function() { 
    toggleDiv(status); 
}); 
1

Usted debe unirse al evento click fuera de la función toggleDiv. El código actual se registrará nuevo manejador click evento cada vez que los elementos en $('#test') se hace clic, con un crecimiento exponencial (ya que todos click manejador anterior generará un nuevo manejador click, por lo que el número de operarios se duplicará con cada clic).

+0

no, el número de controladores aumentará en _one_ con cada clic (es decir, de forma lineal) – Alnitak

+0

@Alnitak: lo he comprobado a través de la consola. El número de veces que se llama a toggleDiv (que es igual al número de veces que se registra el evento click) se duplica cada vez que se hace clic. – nhahtdh

+0

ah sí, entonces sí. Disculpas – Alnitak

1

Tras su caso, está añadiendo otro evento de clic a #test. Llamará a todos los manejadores de clics cuando se haga clic. Probablemente no necesite eso en absoluto ya que onclick se define en el html.

5

La función de clic jQuery no sobrescribe un controlador de clic anterior pero en vez añade el nuevo a una cola. Por lo tanto, cuando se vuelve a llamar, se agrega un nuevo controlador de clics junto con todos los antiguos.

Para evitar esto, sólo tiene que borrar los antiguos controladores antes de definir la nueva.

function toggleDiv(status) 
{ 
    console.log("toggleDiv(" + status + ")"); 
    if (status) { 
     $("#test").html("Goodbye"); 
    } 
    else { 
     $("#test").html("Hello"); 
    } 

    $("#test").unbind(); 

    $("#test").click(function() { 
     toggleDiv(!status); 
    }); 
}​ 

También puede que desee ver en el .toggle() event handler.

ACTUALIZACIÓN: Para ser más claros sobre .toggle(), esto también va a hacer lo que quiere:

$("#test").toggle(
    function(event) { $(event.target).html("Goodbye"); }, 
    function(event) { $(event.target).html("Hello"); } 
); 
+0

Buscaré alternar(). Puede ser lo que necesito. –

+0

Agregué una actualización con una muestra de código que debería ayudarte. –

1

La solución más limpia sería la siguiente: http://jsfiddle.net/kannix/fkMf9/4/

$("#test").click(function() { 
    $(this).text(($(this).text() == "Hello") ? "Goodbye" : "Hello"); 
}); 
+0

Gracias. Esto funciona pero no para mi proyecto. El jsfiddle era solo un ejemplo trivial para probar. –

1

El mismo problema estaba ocurriendo conmigo . La respuesta de Joseph Erickson sobre unbind() funciona. Si ayuda, aquí está el resumen de cómo evento onclick terminó siendo llama varias veces en mi código:

  • llamada AJAX es la actualización de una tabla tbody. El contenido de tbody es totalmente dinámico.
  • Las filas de la tabla se recuperan por lotes (a través de la captura del lado del servidor).
  • A datos de la tabla específicos (td) tenían un hipervínculo que tiene un evento click asociado a ella. (Evento Click añadió como parte de la función de devolución de llamada AJAX)
  • Ahora, cada vez, el AJAX se llama, un evento click se asociado al td.
  • En consecuencia, tantas veces se invoca un AJAX, que muchos manejadores de clics se adjuntan a la td.

Resolví esto según sugerencia dada por Joseph Erickson. Dentro de la devolución de llamada AJAX, hago esto ahora: $ (". MsgLinkDiv"). Unbind(); (".msgLinkDiv"). Clic (función (e) {hacer mis cosas});

Cuestiones relacionadas