2009-08-11 24 views
53

Decir que tengo algo como lo siguiente para atrapar el evento click de un botón:Cómo deshabilitar temporalmente un manejador de clics en jQuery?

$("#button_id").click(function() { 
    //disable click event 
    //do something 
    //re-enable click event 
} 

¿Cómo se desactiva temporalmente el evento click del botón hasta el final del procesamiento del clic original, se produce? Básicamente, tengo el div desaparecer después de hacer clic en el botón, pero si el usuario hace clic varias veces en el botón, procesa todos los clics antes de que el div tenga la oportunidad de desaparecer. Quiero "rebotar" el botón para que solo el primer clic se registre antes de que el div desaparezca.

+0

similar: http://stackoverflow.com/questions/4674991/ intercept-click-event-on-a-button-ask-for-confirmation-then-proceed/4675010 # 4675010 – cregox

+0

3 buenas maneras de hacerlo http://stackoverflow.com/a/1922012/781695 – Medorator

Respuesta

9
$("#button_id").click(function() { 
    if($(this).data('dont')==1) return; 
    $(this).data('dont',1); 
    //do something 
    $(this).data('dont',0); 
} 

Recuerda que $ .data() funcionaría solo para los artículos con identificación.

+0

Me gusta esta solu mejor que la opción .one. He estado trabajando con elementos que pueden estar observando que un solo evento. Al usar .one, o al llamar a .off y .on nuevamente, cambiaría el orden de las devoluciones de llamada. Al agregar un atributo de datos observado por las funciones de devolución de llamada, puede mantener el orden de devolución de llamada intacto – mikeweber

+2

Su regreso anticipado aquí * nunca * tendrá efecto. JavaScript tiene una sola hebra, por lo que si hay varias llamadas a esta función en cola, puede tener la garantía de que cuando se inicie la segunda, la primera habrá terminado y establecerá su atributo 'dont' de nuevo en 0. –

2

Si #button_id implica un botón HTML estándar (como un botón de envío) puede usar el atributo 'deshabilitado' para que el botón quede inactivo en el navegador.

$("#button_id").click(function() { 
    $('#button_id').attr('disabled', 'true'); 

    //do something 

    $('#button_id').removeAttr('disabled'); 
}); 

Con lo que debe tener cuidado, sin embargo, es el orden en que estas cosas pueden suceder. Si está utilizando el comando jquery hide, puede incluir "$ ('# button_id'). RemoveAttr ('disabled');" como parte de una devolución de llamada, para que no suceda hasta que se complete la ocultación.

[editar] ejemplo de función usando una devolución de llamada:

$("#button_id").click(function() { 
    $('#button_id').attr('disabled', 'true'); 
    $('#myDiv').hide(function() { $('#button_id').removeAttr('disabled'); }); 
}); 
+0

Como la mayoría de las respuestas aquí , esta respuesta (o al menos el primer ejemplo de código) es incorrecta: su primer ejemplo * sincrónicamente * desactiva el botón, ejecuta el controlador y vuelve a habilitar el botón, todo * antes * el navegador considera cómo procesar el siguiente clic. Consulte http://jsfiddle.net/at75H/18/ para obtener una demostración de este error al trabajar; si abre la consola y hace clic en el botón muchas veces, verá que el manejador se dispara varias veces, a pesar de agregar el atributo 'disabled '. Debe posponer la eliminación del atributo (por ejemplo, con 'setTimeout') para que esto funcione. –

36

Ésta es una alternativa más idiomática a las soluciones de variables de estado artificial:

$("#button_id").one('click', DoSomething); 

function DoSomething() { 
    // do something. 

    $("#button_id").one('click', DoSomething); 
} 

Una sólo ejecutará una vez (hasta adjunta nuevamente). Más información aquí: http://docs.jquery.com/Events/one

+0

-1; esto no funciona Por ejemplo, intente hacer clic rápidamente en el botón varias veces en este violín: http://jsfiddle.net/at75H/1/ –

+0

@MarkAmery: ¿No es así porque está volviendo a conectar el controlador dentro de la devolución de llamada? Si no lo hace, funciona como se esperaba: http://jsfiddle.net/at75H/2/ –

+1

Vuelva a conectar el controlador dentro de la devolución de llamada en su respuesta, en la cual basé mi violín. Necesita volver a conectarlo en * algún * punto, o si no, está desactivando permanentemente el controlador en lugar de hacerlo temporalmente. Creo que la solución limpia aquí es diferir la reconexión del manejador usando una llamada de 0ms 'setTimeout' - Escribiré una respuesta cuando tenga la oportunidad. –

-2
$("#button_id").click(function() { 
    $('#button_id').attr('disabled', 'true'); 
    $('#myDiv').hide(function() { $('#button_id').removeAttr('disabled'); }); 
}); 

No utilice .attr() hacer las personas con discapacidad, utilizar .prop(), es mejor.

+0

¿Por qué es mejor? – reformed

-1

Este ejemplo funciona.


código HTML:

<div class="wrapper"> 
    <div class="mask">Something</div> 
    </div> 

jQuery:

var fade = function(){ 
     $(".mask").fadeToggle(500,function(){ 
      $(this).parent().on("click",function(){ 
       $(this).off("click"); 
       fade(); 
      }); 
     }); 
    }; 

    $(".wrapper").on("click",function(){ 
     $(this).off("click"); 
     fade();  
    }); 
-2

Este código se mostrará carga en la etiqueta del botón y botón configurado para deshabilitar el estado, a continuación, después del procesamiento, vuelva a habilitar y devolver el texto del botón original:

$(function() { 

     $(".btn-Loading").each(function (idx, elm) { 
      $(elm).click(function() { 
       //do processing 
       if ($(".input-validation-error").length > 0) 
        return; 
       $(this).attr("label", $(this).text()).text("loading ...."); 
       $(this).delay(1000).animate({ disabled: true }, 1000, function() { 
        //original event call 
        $.when($(elm).delay(1000).one("click")).done(function() { 
         $(this).animate({ disabled: false }, 1000, function() { 
          $(this).text($(this).attr("label")); 
         }) 
        }); 
        //processing finalized 
       }); 
      }); 
     }); 
     // and fire it after definition 
    } 
    ); 
43

Me di cuenta de que esta publicación era antigua, pero aparece en la parte superior de Google y este tipo de solución nunca se ofreció, así que decidí publicarla de todos modos.

Puede deshabilitar eventos de cursor y habilitarlos de nuevo más tarde mediante css. Es compatible con todos los principales navegadores y puede resultar útil en algunas situaciones.

$("#button_id").click(function() { 

    $("#button_id").css("pointer-events", "none"); 
    //do something 
    $("#button_id").css("pointer-events", "auto"); 
} 
+0

Esta es una buena solución en teoría, pero no es universalmente compatible: el soporte de IE comenzó solo a partir de la versión 11. Esto significa que actualmente quedan muchos navegadores para los que debe buscar otra solución. –

+0

Existen formas sencillas de arreglarlo para versiones anteriores de IE si aún necesita soporte para ellas (puede usar el código anterior en las aplicaciones móviles wp8 HTML5 pero no en 7). En versiones anteriores, recomendaría usar este método para solucionarlo http://www.vinylfox.com/forwarding-mouse-events-through-layers/ – Defain

+0

¡Respuesta totalmente subestimada! Todo lo demás que encontré hasta la fecha fue simplemente un truco. – pmkrefeld

2

Puede hacerlo como las otras personas antes que yo te dije usando un vistazo:

A.) Utilice .data del elemento de botón para compartir una variable mirada (o simplemente una variable global)

if ($('#buttonId').data('locked') == 1) 
    return 
$('#buttonId').data('locked') = 1; 
// Do your thing 
$('#buttonId').data('locked') = 0; 

B.) señales desactivar ratón

$("#buttonId").css("pointer-events", "none"); 
// Do your thing 
$("#buttonId").css("pointer-events", "auto"); 

C) Si se trata de un botón HTML se puede desactivar (entrada [ty pe = enviar] o botón)

$("#buttonId").attr("disabled", "true"); 
// Do your thing 
$("#buttonId").attr("disabled", "false"); 

¡Pero ten cuidado con otros hilos! Fallé muchas veces porque mi animación (desvaneciéndose o desapareciendo) tardó un segundo. P. ej. fadeIn/fadeOut admite una función de devolución de llamada como segundo parámetro. Si no hay otra manera, solo hazlo usando setTimeout(callback, delay).

saluda, Thomas

+1

JavaScript ejecutado en el navegador es de un solo hilo; No sé a qué te refieres con "ten cuidado con otros hilos", pero estoy bastante seguro de que estás malinterpretando lo que está pasando. –

+1

puntero-eventos es el camino a seguir para los enlaces, pero la compatibilidad solo se aplica a IE 11. –

4

Puede desvincular el controlador con .off, pero hay una advertencia; Si está haciendo esto, solo evite que el manejador se dispare de nuevo mientras se está ejecutando, necesita diferir la reenlace del manejador.

Por ejemplo, considere este código, que utiliza a 5 segundos del sueño caliente para simular algo sincrónico y costoso computacionalmente que se realiza desde dentro del controlador (como la manipulación DOM pesada, por ejemplo):

<button id="foo">Click Me!</div> 
<script> 
    function waitForFiveSeconds() { 
     var startTime = new Date(); 
     while (new Date() - startTime < 5000) {} 
    } 
    $('#foo').click(function handler() { 
     // BAD CODE, DON'T COPY AND PASTE ME! 
     $('#foo').off('click'); 
     console.log('Hello, World!'); 
     waitForFiveSeconds(); 
     $('#foo').click(handler); 
    }); 
</script> 

Este won no funciona Como puede ver si lo prueba en this JSFiddle, si hace clic en el botón mientras el controlador ya se está ejecutando, el controlador ejecutará una segunda vez una vez que finalice la primera ejecución. Además, al menos en Chrome y Firefox, esto sería cierto incluso si no usó jQuery y usó addEventListener y removeEventListener para agregar y eliminar el controlador en su lugar. El navegador ejecuta el controlador después del primer clic, desvincula y vuelve a vincular el controlador, y luego maneja el segundo clic y verifica si hay un controlador de clic para ejecutar.

Para evitar esto, es necesario aplazar la reconsolidación del controlador usando setTimeout, por lo que los clics que se producen mientras el primer controlador está ejecutando serán procesados ​​ antes de volver a adjuntar el manejador.

<button id="foo">Click Me!</div> 
<script> 
    function waitForFiveSeconds() { 
     var startTime = new Date(); 
     while (new Date() - startTime < 5000) {} 
    } 
    $('#foo').click(function handler() { 
     $('#foo').off('click'); 
     console.log('Hello, World!'); 
     waitForFiveSeconds(); 

     // Defer rebinding the handler, so that any clicks that happened while 
     // it was unbound get processed first. 
     setTimeout(function() { 
      $('#foo').click(handler); 
     }, 0); 
    }); 
</script> 

Puedes ver esto en acción en this modified JSFiddle.

Naturalmente, esto es innecesario si lo que está haciendo en su controlador ya es asincrónico, ya que entonces ya está cediendo el control al navegador y dejando que elimine todos los eventos de clic antes de volver a vincular su controlador.Por ejemplo, un código como esto va a funcionar bien sin una llamada setTimeout:

<button id="foo">Save Stuff</div> 
<script> 
    $('#foo').click(function handler() { 
     $('#foo').off('click'); 
     $.post("/some_api/save_stuff", function() { 
      $('#foo').click(handler); 
     }); 
    }); 
</script> 
+0

Gracias por esto.Me encontré con este problema exacto en los últimos días donde necesitaba desvincular temporalmente un evento de enfoque que estamos usando. –

0

Intenta utilizando .one()

var button = $("#button"), 
 
    result = $("#result"), 
 
    buttonHandler = function buttonHandler(e) { 
 
    result.html("processing..."); 
 
    $(this).fadeOut(1000, function() { 
 
     // do stuff 
 
     setTimeout(function() { 
 
     // reset `click` event at `button` 
 
     button.fadeIn({ 
 
      duration: 500, 
 
      start: function() { 
 
      result.html("done at " + $.now()); 
 
      } 
 
     }).one("click", buttonHandler); 
 

 
     }, 5000) 
 
    }) 
 
    }; 
 

 
button.one("click", buttonHandler);
#button { 
 
    width: 50px; 
 
    height: 50px; 
 
    background: olive; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"> 
 
</script> 
 
<div id="result"></div> 
 
<div id="button">click</div>

+0

Casi lancé un -1 en esto, pero tal vez estoy siendo muy duro. A diferencia de la mayoría de las respuestas, esto * funciona * (ya que difiere la lectura del controlador con 'setTimeout'), pero no hay ninguna explicación de lo que está sucediendo; No creo que esto me sea útil si no comprendiera la necesidad de aplazar la lectura del controlador. –

+0

@MarkAmery _ Casi lancé un -1 en esto, pero quizás estoy siendo demasiado duro. A diferencia de la mayoría de las respuestas, esto funciona (ya que posterga la lectura del controlador con 'setTimeout'), pero no hay ninguna explicación de lo que está sucediendo_ El enfoque real es utilizar' .one() '. 'setTimeout',' .fadeOut() ',' .fadeIn() 'fueron para propósitos de demostración de usar' .one() '. Es decir, el evento se llama a lo sumo una vez; Vuelva a unir el evento usando '.one()' cuando se completen todos los procesos síncronos o asíncronos. Si se hace clic en 'botón' antes de completar las tareas, no se adjuntaría ningún evento; se adjunta evento, se vuelve a conectar uno a la vez – guest271314

Cuestiones relacionadas