2009-11-27 13 views
18

Esiste un modo elegante per sopprimere temporaneamente gli eventi jQuery? Io uso il codice come questo:Sospendi temporaneamente la gestione degli eventi jQuery

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

ma lo trovo un po 'goffo e non molto scalabile a molti eventi. Perché voglio sopprimere temporaneamente gli eventi? Uso il plug-in BlockUI per bloccare l'interfaccia utente durante l'accesso Ajax. Questo è fatto con: $(). AjaxStart ($. BlockUI) .ajaxStop ($ .unblockUI) come proposto da BlockUI.

Tuttavia, un accesso Ajax è speciale, quindi ho bisogno di un messaggio diverso. Gli eventi ajaxStart e ajaxStop interferiscono con il codice messaggio (non viene mostrato nulla):

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

Solo se mi togliere il commento alla unbind() e bind) linee (, si sta lavorando.

risposta

14

mi rendo conto questa domanda è vecchia, ma ho trovato che mentre cerca una risposta alla stessa domanda, e abbiamo finito per trovare una soluzione diversa che funziona bene in semplici applicazioni di gestori di eventi.

$(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'); 
    } 
} 

La semplice aggiunta di una classe per il vostro 'elemento di mentre il codice dall'evento sta sparando consente di impedire un ulteriore codice venga eseguito come il risultato di un altro evento click. Pertanto, mentre non stai effettivamente impedendo altri eventi di clic, stai impedendo l'esecuzione del codice risultante. Semplice, grezzo, ignora l'uso pesantemente predicato di legare e sciogliere, ma funziona.

+0

Vuoi dire , impedendo il codice risultante da RUNNING? – nalply

+0

Perché sì * modifica la risposta *, non è quello che ho detto? Mi sono fatto prendere dagli handler di eventi e da tutti i licenziamenti che ho fatto ho abusato della parola. – Eric

+0

Nessun problema, hai modificato la risposta. Benvenuti in Stackoverflow. – nalply

4

Il modo più semplice per eseguire questa operazione è aggiungere un controllo all'inizio del metodo associato per determinare se il metodo deve essere eseguito. In caso contrario, è sufficiente tornare dal metodo.

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

Si tratta di un linguaggio ben noto. È necessario se il gestore eventi attiva in qualche modo il proprio evento e quindi viene richiamato in modo ricorsivo, causando loop infiniti, rendendo il browser non rispondente. Ma questo non è il mio problema. Non ho una ricorsione indesiderata. Il mio problema è che altri gestori di eventi interferiscono con il mio codice, quindi ho bisogno di sopprimere temporaneamente la gestione degli eventi. Il codice dell'altro gestore di eventi si trova in BlockUI stesso, quindi no, non posso modificarlo. – nalply

1

L'idea è di bloccare la pagina, generare più richieste di ajax (concatenate o meno) e quindi sbloccare la pagina?

Se questo è il caso (e ho capito correttamente la domanda), allora si potrebbe usare un contatore di blocchi?

ad es. var blockcounter = 0;

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

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

poi nel codice

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(); 

Blocco dovrebbe verificarsi una volta solo allora e tu sei libero di fare quello in mezzo.

Uso questo metodo correttamente su un sito Web in cui si verificano più eventi tra il blocco e lo sblocco e dove i diversi eventi Ajax possono essere completati in tempi diversi. Se avvolgi tutto il lotto in uno spazio dei nomi puoi anche evitare di sporcare il posto con le vars globali.

+1

Sì, ho usato prima un contatore di blocchi. . Ma $() ajaxStart (. $ BlockUI) .ajaxStop (. $ UnblockUI) è più ordinato - lo fa il blocco e sblocco per voi, ma interferirà come è successo a me nel messaggio(). per favore cerchiamo di attaccare con la domanda iniziale: come sopprimere temporaneamente la gestione degli eventi. Forse nel senso di un meccanismo di sospensione/ripresa. – nalply

10

costano finire questo script, spero che sia utile:

<!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

Wow! Hai scritto un piccolo plugin jQuery! Quindi pensi che non ci sia un trucco facile da sospendere/riprendere generalmente (o come si chiama freeze/unfreeze) nella gestione degli eventi in jQuery? – nalply

+0

rivedere la libreria jQuery, ho visto meglio creare questo plugin. Devi provare a scoprire se ti è utile –

+0

Come funzionano il congelamento e il unfreeze? A proposito, conosci il plugin jQuery di CopyEvents? http://plugins.jquery.com/project/copyEvents – nalply

5

Mi è piaciuto molto l'approccio di Andres a questo problema, ma sembra che da quando è uscito con quel codice, il modello di eventi jQuery è cambiato, quindi nelle ultime versioni di jQuery il suo codice non funziona. Qui è modernizzato. Testato (leggermente) in 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); 
     }); 
    }; 

Non ho provato questo oltre un elemento con due eventi, ma funziona bene per me. Spero che questo aiuti qualcuno.

+0

ho tolto il controllo namespacing, ho usato di jQuery ogni metodo per iterare sugli eventi, e le espressioni refactoring di utilizzare il nuovo modello di eventi jQuery. Se confronti il ​​codice, vedrai le differenze, sono abbastanza ovvi. –

+0

Grazie. Ero troppo pigro per un diff. – nalply

1

Si può semplicemente salvare e ripristinare l'intero eventi oggetto:

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 

questo ha funzionato per me, ma possono avere effetti collaterali sconosciuti ...

+0

Mi piace questo metodo e penso che sia un buon approccio – abzarak

Problemi correlati