2009-11-27 9 views
18

¿Existe alguna manera elegante de suprimir temporalmente los eventos de jQuery? Uso un código como este:Suprima el manejo de eventos de jQuery temporalmente

$(element).unbind(event, function1).unbind(event, function2); 
// code for which the event is suppressed 
$(element).bind(event, function1).bind(event, function2); 

pero me parece un poco torpe y no muy escalable para muchos eventos. ¿Por qué quiero suprimir eventos temporalmente? Uso el complemento BlockUI para bloquear la IU durante el acceso a Ajax. Esto se hace con: $(). AjaxStart ($. BlockUI) .ajaxStop ($. UnblockUI) según lo propuesto por BlockUI.

Sin embargo, un acceso Ajax es especial, por lo que necesito un mensaje diferente. Los eventos ajaxStart y ajaxStop interfieren con el código del mensaje (no se muestra nada):

function message(text, callback) { 
    if (text == undefined) { 
    $.unblockUI(); 
    return; 
    } 

    // $().unbind('ajaxStop', $.unblockUI).unbind('ajaxStart', $.blockUI); 
    $("#message_text").html(text); 
    $.blockUI({message: $("#message")}); 
    $("#message_ok").click(function() { 
    // $().bind('ajaxStop', $.unblockUI).bind('ajaxStart', $.blockUI); 
    $.unblockUI(); 
    if (callback != undefined) callback(); 
    }); 
} 

Sólo si me elimine el comentario) líneas (unbind() y el enlace, se está trabajando.

Respuesta

14

que dan cuenta de esta pregunta es viejo, pero me pareció que mientras se busca una respuesta a la misma pregunta, y terminamos encontrar una solución diferente que funciona bien en aplicaciones simples de controladores de eventos.

$(element).click(function(e) { 
    e.preventDefault(); 

    // Check for fired class 
    if ($(this).hasClass('fired') == false) { 
    // Add fired class to all instances of element 
    $(element).addClass('fired'); 

    // Do the rest of the function... 

    // Remove fired class to 'reactivate' events 
    $(element).removeClass('fired'); 
    } 
} 

Simplemente añadiendo una clase a su 'elemento de mientras que el código del evento está disparando le permite evitar que más código se ejecute como el resultado de otro evento de clic. Por lo tanto, si bien no previene ningún otro evento de clic, impide que se ejecute el código resultante. Simple, grosero, ignora el uso tan profetizado de vincular y desvincular, pero funciona.

+0

Se refiere a , evitando que el código resultante se EJECUTE? – nalply

+0

Por qué sí * edita la respuesta *, ¿no es eso lo que dije? Me quedé atrapado en los manejadores de eventos y todos los disparos que hacen que mal uso la palabra. – Eric

+0

No hay problema, editó la respuesta. Bienvenido a Stackoverflow. – nalply

4

La forma más sencilla de hacerlo es agregar una marca al principio del método enlazado para determinar si el método debe ejecutarse. Si no, simplemente regrese del método.

var doThing = true; 

$("#foo").bind("click", function(e) { 
    if(!doThing){return;} 
    //do thing 
} 

function bar(){ 
    //temp unbind click 
    doThing = false; 

    //do stuff... 

    //rebind click 
    doThing = true; 
} 
+1

Este es un lenguaje conocido. Es necesario si el controlador de eventos desencadena de algún modo su propio evento y, por lo tanto, se invoca recursivamente, lo que genera un bucle infinito, lo que hace que el navegador no responda. Pero este no es mi problema. No tengo recursión no deseada. Mi problema es que otros controladores de eventos interfieren con mi código, por lo que necesito suprimir el manejo de eventos temporalmente. El código del otro manejador de eventos está en BlockUI, entonces, no, no puedo modificarlo. – nalply

1

Así es la idea de bloquear la página, disparar múltiples peticiones Ajax (encadenados o no) y luego desbloquear la página?

Si ese es el caso (y he entendido la pregunta correctamente), ¿podría usar un contador de bloque?

p. Ej. var blockcounter = 0;

function block(){ 
if(blockcounter==0) 
{$.blockUI({message: "Hai", showOverlay:true});} 
blockcounter++; 
} 

function unblock(){ 
blockcounter--; 
if(blockcounter==0) 
{$.unblockUI();} 
} 

a continuación en el código

function dostuff(){ 
block(); 
... do whatever ajax you need 
... call unblock() in the success event of your ajax call 
} 

function dostuff2(){ 
block(); 
... do some more ajax - this might take a bit longer to complete though 
... call unblock() in the success event 
} 

dostuff(); 
dostuff2(); 

El bloqueo debe ocurrir sólo una vez entonces y usted es libre de hacer lo que en el medio.

Utilizo este método con éxito en un sitio web donde ocurren múltiples eventos entre el bloqueo y el desbloqueo y donde los diferentes eventos ajax pueden completarse en diferentes momentos. Si envuelve todo el lote en un espacio de nombres, también puede evitar ensuciar el lugar con variables globales.

+1

Sí, utilicé primero un contador de bloque. Pero $(). AjaxStart ($. BlockUI) .ajaxStop ($. UnblockUI) es más nítido: realiza el bloqueo y desbloqueo por usted, pero interferirá como me sucedió en message(). Mantengámonos con la pregunta original: cómo suprimir el manejo de eventos temporalmente. Tal vez en el sentido de un mecanismo de suspender/reanudar. – nalply

10

cuestan a terminar esta secuencia de comandos, espero que sea útil:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" /> 
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script> 
<script type="text/javascript"> 
$(function(){ 

    //ini plugin 

    jQuery.event.freezeEvents = function(elem) { 

     if (typeof(jQuery._funcFreeze)=="undefined") 
      jQuery._funcFreeze = []; 

     if (typeof(jQuery._funcNull)=="undefined") 
      jQuery._funcNull = function(){ }; 

     // don't do events on text and comment nodes 
     if (elem.nodeType == 3 || elem.nodeType == 8) 
      return; 

     var events = jQuery.data(elem, "events"), ret, index; 

     if (events) { 

      for (var type in events) 
      { 
       if (events[type]) { 

        var namespaces = type.split("."); 
        type = namespaces.shift(); 
        var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)"); 

        for (var handle in events[type]) 
         if (namespace.test(events[type][handle].type)){ 
          if (events[type][handle] != jQuery._funcNull){ 
           jQuery._funcFreeze["events_freeze_" + handle] = events[type][handle]; 
           events[type][handle] = jQuery._funcNull; 
          } 
         } 
       } 

      } 
     } 
    } 

    jQuery.event.unFreezeEvents = function(elem) { 

     // don't do events on text and comment nodes 
     if (elem.nodeType == 3 || elem.nodeType == 8) 
      return; 

     var events = jQuery.data(elem, "events"), ret, index; 

     if (events) { 

      for (var type in events) 
      { 
       if (events[type]) { 

        var namespaces = type.split("."); 
        type = namespaces.shift(); 

        for (var handle in events[type]) 
         if (events[type][handle]==jQuery._funcNull) 
          events[type][handle] = jQuery._funcFreeze["events_freeze_" + handle]; 

       } 
      } 
     } 
    } 

    jQuery.fn.freezeEvents = function() { 

     return this.each(function(){ 
      jQuery.event.freezeEvents(this); 
     }); 

    }; 

    jQuery.fn.unFreezeEvents = function() { 

     return this.each(function(){ 
      jQuery.event.unFreezeEvents(this); 
     }); 

    }; 

    //end plugin 

    jQuery("#test1").ajaxStart(function test1(){ 
     jQuery("#result").append('test1 ajaxStop<br>'); 
    }); 

    jQuery("#test1").ajaxStop(function test2(){ 
     jQuery("#result").append('test1 click<br>'); 
    }); 

    jQuery("#test1").bind("click", function test3(){ 
     jQuery("#result").append('test1 click<br>'); 
    }); 

    jQuery("#test2").bind("click", function test5(){ 
     jQuery("#result").append('test2 click<br>'); 
    }); 

    jQuery("#freez").click(function(){ 
     jQuery("#test1").freezeEvents(); 
     jQuery("#test2").freezeEvents(); 
    }); 

    jQuery("#unfreez").click(function(){ 
     jQuery("#test1").unFreezeEvents(); 
     jQuery("#test2").unFreezeEvents(); 
    }); 

}); 
</script> 
</head> 
<body> 
<button id="freez">freez</button> 
<button id="unfreez">un freez</button> 
<br /> 
<div id="test1">test1 click mousemove</div> 
<div id="test2">test2 click mousemove</div> 
<br /> 
<div id="result"></div> 
</body> 
</html> 
+0

¡Guau! ¡Escribiste un pequeño plugin jQuery! ¿Entonces piensas que no hay un truco fácil para suspender/reanudar (o cuando llamas congelar/descongelar) el manejo de eventos en jQuery? – nalply

+0

revisando la biblioteca jQuery, vi que era mejor hacer este complemento. Debe intentar averiguar si es útil –

+0

¿Cómo funciona la congelación y la descongelación? Por cierto, ¿conoces el plugin CopyEvents jQuery? http://plugins.jquery.com/project/copyEvents – nalply

5

Me gustó mucho el enfoque de Andres a este problema, pero parece que desde que se le ocurrió el código, el modelo de eventos jQuery ha cambiado, por lo que en versiones recientes de jQuery su código no funciona. Aquí está modernizado. Probado (ligeramente) en 1.8.2:

$.event.freezeEvents = function(elem) { 

     if (typeof($._funcFreeze)=="undefined") { 
      $._funcFreeze = []; 
     } 

     if (typeof($._funcNull)=="undefined") { 
      $._funcNull = function() {}; 
     }     

     // don't do events on text and comment nodes 
     if (elem.nodeType == 3 || elem.nodeType == 8) { 
      return; 
     } 

     var events = $._data(elem, "events"); 

     if (events) { 
      $.each(events, function(type, definition) { 
       $.each(definition, function(index, event) { 
        if (event.handler != $._funcNull){ 
         $._funcFreeze["events_freeze_" + event.guid] = event.handler; 
         event.handler = $._funcNull; 
        } 
       }) 
      }) 
     } 
    } 

    $.event.unFreezeEvents = function(elem) { 

     // don't do events on text and comment nodes 
     if (elem.nodeType == 3 || elem.nodeType == 8) 
       return; 

     var events = $._data(elem, "events"); 

     if (events) { 
      $.each(events, function(type, definition) { 
       $.each(definition, function(index, event) { 
        if (event.handler == $._funcNull){ 
         event.handler = $._funcFreeze["events_freeze_" + event.guid]; 
        } 
       }) 
      }) 
     } 
    } 

    $.fn.freezeEvents = function() { 
     return this.each(function(){ 
      $.event.freezeEvents(this); 
     }); 
    }; 

    $.fn.unFreezeEvents = function() { 
     return this.each(function(){ 
      $.event.unFreezeEvents(this); 
     }); 
    }; 

No he probado esto más allá de un elemento con dos eventos, pero funciona bien para mí. Espero que esto ayude a alguien.

+0

Quité la comprobación del espacio de nombres, utilicé cada método de jQuery para iterar sobre los eventos y reformé las expresiones para usar el nuevo modelo de evento jQuery. Si comparas el código, verás las diferencias, son bastante obvias. –

+0

Gracias. Yo era demasiado flojo para una diferencia. – nalply

1

Simplemente puede guardar y restaurar todo el objeto de los acontecimientos:

var events=$._data(elem, 'events'); // save events 
$._data(elem, 'events', {}); // cancel all events 
// any code here will not fire events 
$._data(elem, 'events', events); // restore events 

Esto funcionó para mí, pero pueden tener efectos secundarios desconocidos ...

+0

Me gusta este método y creo que es un buen enfoque – abzarak

Cuestiones relacionadas