2009-11-27 2 views
18

Есть ли элегантный способ временно запретить события jQuery? Я использую такой код:Временно отключить обработку событий jQuery

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

, но я нахожу его немного неуклюжим и не очень масштабируемым для многих событий. Почему я хочу временно отключать события? Я использую плагин BlockUI для блокировки интерфейса во время доступа Ajax. Это делается с помощью: $(). AjaxStart ($. BlockUI) .ajaxStop ($. UnblockUI) как предложено BlockUI.

Однако один доступ Ajax является особенным, поэтому мне нужно другое сообщение. События ajaxStart и ajaxStop вмешиваться в код сообщения (ничего не отображается):

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

Только если я раскомментировать отвязать() и привязку() линии, она работает.

ответ

14

Я понимаю, что этот вопрос старый, но я нашел его, ища ответ на тот же вопрос, и в конечном итоге найти другое решение, хорошо работает в простых приложениях обработчиков событий.

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

Просто добавив класс вашего «элемента в то время как код от события стрельбы позволяет предотвратить дальнейший код из выполняются в результате другого события щелчка. Поэтому, в то время как вы фактически не предотвращаете какие-либо другие события кликов, вы запрещаете запуск этого кода. Простой, грубый, игнорирует сильно проповедуемое использование связывания и развязывания, но работает.

+0

Вы имеете в виду , предотвращая запуск кода из RUNNING? – nalply

+0

Почему да * редактирует ответ *, разве это не то, что я сказал? Я все поймал в обработчиках событий и все, что они стреляли, что я неправильно использовал это слово. – Eric

+0

Нет проблем, вы отредактировали ответ. Добро пожаловать в Stackoverflow. – nalply

4

Самый простой способ сделать это - добавить проверку в начале связанного метода, чтобы определить, должен ли этот метод работать. Если нет, просто вернитесь из метода.

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

Это хорошо известная идиома. Это необходимо, если обработчик событий каким-то образом запускает свое собственное событие и, следовательно, рекурсивно вызывается, приводя к бесконечному циклу, что делает браузер невосприимчивым. Но это не моя проблема. У меня нет нежелательной рекурсии. Моя проблема в том, что другие обработчики событий мешают моему коду, поэтому мне нужно временно отключить обработку событий. Код другого обработчика событий находится в BlockUI, поэтому нет, я не могу его изменить. – nalply

1

Так ли это идея блокировать страницу, запускать несколько запросов ajax (в цепочке или в другом случае), а затем разблокировать страницу?

Если это так (и я правильно понял вопрос), вы можете использовать счетчик блоков?

например. var blockcounter = 0;

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

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

затем в коде

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

Блокирование должно происходить только один раз, то и вы свободны делать все, что в середине.

Я использую этот метод успешно на веб-сайте, где происходит несколько событий между блокировкой и разблокировкой и где различные события ajax могут выполняться в разное время. Если вы обернете всю партию в пространстве имен, вы также можете избежать засорения места глобальными варами.

+1

Да, я сначала использовал блок-счетчик. Но $(). AjaxStart ($. BlockUI) .ajaxStop ($. UnblockUI) более аккуратный - он блокирует и разблокирует для вас, но будет мешать, как это случилось со мной в message(). Пожалуйста, давайте придерживаться оригинального вопроса: как временно отключить обработку событий. Возможно, в смысле механизма приостановки/возобновления. – nalply

10

стоил мне закончить этот сценарий, я надеюсь, что это полезно:

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

Вау! Вы написали небольшой плагин jQuery! Итак, вы думаете, что нет простого трюка, чтобы вообще приостанавливать/возобновлять (или как вы вызываете замораживание/размораживание) обработку событий в jQuery? – nalply

+0

, рассматривая библиотеку jQuery, я видел, как лучше всего сделать этот плагин. Должен попытаться выяснить, полезны ли вы –

+0

Как замораживать и размораживать работу? Кстати, знаете ли вы плагин CopyEvents jQuery? http://plugins.jquery.com/project/copyEvents – nalply

5

Мне очень понравился подход Андреса к этой проблеме, но, похоже, что с его помощью модель события jQuery изменилась, поэтому в последних версиях jQuery его код не работает. Здесь он модернизирован. Протестировано (слегка) в 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); 
     }); 
    }; 

Я не тестировал это за элементом с двумя событиями, но он отлично работает для меня. Надеюсь, это поможет кому-то.

+0

Я удалил проверку имен, я использовал каждый метод jQuery для итерации по событиям и реорганизовал выражения для использования новой модели событий jQuery. Если вы сравните код, вы увидите различия, они совершенно очевидны. –

+0

Спасибо. Я был слишком ленив для разницы. – nalply

1

Вы можете просто сохранить и восстановить объект целые события:

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 

Это работает для меня, но может иметь неизвестные побочные эффекты ...

+0

Мне нравится этот метод и думаю, что это хороший подход – abzarak

Смежные вопросы