2009-11-27 20 views
18

Gibt es eine elegante Möglichkeit, jQuery-Ereignisse vorübergehend zu unterdrücken? Ich benutze Code wie folgt:jQuery-Ereignisbehandlung vorübergehend unterdrücken

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

aber ich finde es ein wenig ungeschickt und nicht sehr skalierbar für viele Ereignisse. Warum möchte ich Ereignisse vorübergehend unterdrücken? Ich verwende das BlockUI-Plugin, um die Benutzeroberfläche während des Ajax-Zugriffs zu blockieren. Dies geschieht mit: $(). AjaxStart ($. BlockUI) .ajaxStop ($. UnblockUI) wie von BlockUI vorgeschlagen.

Allerdings ist ein Ajax-Zugriff speziell, deshalb brauche ich eine andere Nachricht. Die ajaxStart und ajaxStop Ereignisse stören den Nachrichtencode (nichts wird angezeigt):

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

Nur wenn ich die unbind Kommentar-() und die bind() Linien, es funktioniert.

Antwort

14

Ich weiß, diese Frage ist alt, aber ich fand es während einer Antwort auf die gleiche Frage zu suchen, und am Ende eine andere Lösung zu finden, die funktioniert gut in einfachen Anwendungen von Event-Handlern.

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

Hinzufügen einfach eine Klasse zu Ihrem ‚Elements, während der Code aus dem Ereignis ermöglicht feuert Sie von der weiteren Code zu verhindern, wie das Ergebnis einer anderen Click-Ereignis ausgeführt wird. Während Sie also keine anderen Klickereignisse verhindern, verhindern Sie, dass der resultierende Code ausgeführt wird. Einfach, grob, ignoriert den stark gepredigten Einsatz von Bind und Unbind, funktioniert aber.

+0

Sie meinen , verhindert, dass der resultierende Code ausgeführt wird? – nalply

+0

Warum ja * edits antwort *, habe ich das nicht gesagt? Ich habe mich in Ereignishandler und die ganze Brandstiftung verfangen, dass ich das Wort missbraucht habe. – Eric

+0

Kein Problem, Sie haben die Antwort bearbeitet. Willkommen bei Stackoverflow. – nalply

4

Die einfachste Möglichkeit besteht darin, am Anfang der gebundenen Methode eine Überprüfung hinzuzufügen, um festzustellen, ob die Methode ausgeführt werden soll. Wenn nicht, kehren Sie einfach von der Methode zurück.

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

Dies ist eine bekannte Redewendung. Dies ist erforderlich, wenn der Event-Handler sein eigenes Event auslöst und daher rekursiv aufgerufen wird, was zu einer Endlos-Schleife führt, wodurch der Browser nicht mehr reagiert. Aber das ist nicht mein Problem. Ich habe keine unerwünschte Rekursion. Mein Problem ist, dass andere Event-Handler meinen Code stören, daher muss ich die Ereignisbehandlung vorübergehend unterdrücken. Der Code des anderen Ereignishandlers befindet sich in BlockUI selbst, also, nein, ich kann ihn nicht ändern. – nalply

1

So ist die Idee, die Seite zu blockieren, mehrere Ajax-Anfragen (verkettet oder anderweitig) zu feuern und dann die Seite zu entsperren?

Wenn das der Fall ist (und ich habe die Frage richtig verstanden), dann könnten Sie einen Blockzähler verwenden?

z.B. var blockcounter = 0;

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

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

dann in Ihrem Code

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

Blocking sollte einmal treten nur dann und Sie sind frei, was auch immer in der Mitte zu tun.

Ich verwende diese Methode erfolgreich auf einer Website, wo mehrere Ereignisse zwischen Blockierung und Entsperrung passieren und wo die verschiedenen Ajax-Ereignisse in unterschiedlichen Zeiten abgeschlossen werden können. Wenn Sie die gesamte Menge in einem Namensraum einschließen, können Sie auch vermeiden, den Platz mit globalen Variablen zu verunreinigen.

+1

Ja, ich habe zuerst einen Blockzähler benutzt. Aber $(). AjaxStart ($. BlockUI) .ajaxStop ($. UnblockUI) ist sauberer - es macht das Blockieren und Entsperren für Sie, aber wird stören, wie es mir in message() passiert ist. Bleiben wir bei der ursprünglichen Frage: Wie kann die Ereignisbehandlung vorübergehend unterdrückt werden? Vielleicht im Sinne eines Suspend/Resume-Mechanismus. – nalply

10

kostete ich dieses Skript fertig, ich hoffe, dass es nützlich ist:

<!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! Du hast ein kleines jQuery-Plugin geschrieben! Sie denken also, dass es keinen einfachen Trick gibt, die Ereignisbehandlung in jQuery generell zu unterbrechen/fortzusetzen (oder wie Sie freeze/unfreeze aufrufen)? – nalply

+0

Überprüfung der jQuery-Bibliothek sah ich es am besten, dieses Plugin zu machen. Muss versuchen, herauszufinden, ob Sie nützlich sind –

+0

Wie funktioniert das Einfrieren und Entfrosten? Übrigens, kennen Sie das CopyEvents jQuery Plugin? http://plugins.jquery.com/project/copyEvents – nalply

5

Ich mochte Andres 'Herangehensweise an dieses Problem sehr, aber es scheint, dass das jQuery-Ereignismodell sich geändert hat, seitdem er diesen Code entwickelt hat, so dass in den letzten Versionen von jQuery sein Code nicht funktioniert. Hier wird es modernisiert. Getestet (leicht) 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); 
     }); 
    }; 

Ich habe dies nicht über ein Element mit zwei Ereignissen getestet, aber es funktioniert gut für mich. Hoffe, das hilft jemandem.

+0

Ich entfernte die Namespacing-Prüfung, ich verwendete jQuery jede Methode zum Iterieren über die Ereignisse und refactored Ausdrücke, um das neue jQuery-Ereignismodell zu verwenden. Wenn Sie den Code vergleichen, werden Sie die Unterschiede sehen, sie sind ziemlich offensichtlich. –

+0

Danke. Ich war zu faul für einen Unterschied. – nalply

1

Sie können einfach speichern und wiederherstellen die gesamten Ereignisse Objekt:

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 

Das ist für mich gearbeitet, aber können unbekannte Nebenwirkungen haben ...

+0

Ich mag diese Methode und denke, es ist ein guter Ansatz – abzarak