如何暂时禁用jQuery中的单击处理程序?

64 javascript jquery

假设我有类似以下内容来捕获按钮的click事件:

$("#button_id").click(function() {
  //disable click event
  //do something
  //re-enable click event
}
Run Code Online (Sandbox Code Playgroud)

如何暂时禁用按钮的单击事件,直到原始单击处理结束?单击按钮后,我基本上消除了div,但如果用户快速点击按钮几次,它会在div有机会消失之前处理所有这些点击.我想"去抖动"按钮,以便在div消失之前只有第一次点击才会被注册.

Def*_*ain 64

我注意到这篇文章很老但是它似乎在google上排名第一,而且从未提供过这种解决方案,所以无论如何我决定发布它.

你可以禁用游标事件,稍后再通过css启用它们.它在所有主流浏览器上都受支持,在某些情况下可能会很有用.

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

   $("#button_id").css("pointer-events", "none");
   //do something
   $("#button_id").css("pointer-events", "auto");
}
Run Code Online (Sandbox Code Playgroud)


Dav*_*ard 37

这是人工状态变量解决方案的更惯用的替代方案:

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

function DoSomething() {
  // do something.

  $("#button_id").one('click', DoSomething);
}
Run Code Online (Sandbox Code Playgroud)

一个人只会执行一次(直到再次附加).更多信息:http: //docs.jquery.com/Events/one

  • -1; 这是行不通的。例如,尝试在此小提琴中多次快速单击按钮:http://jsfiddle.net/at75H/1/ (2认同)

Thi*_*ker 10

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

记住$ .data()仅适用于具有ID的项目.

  • 你早日的回归将永远*永远不会生效.JavaScript是单线程的,所以如果有几个对这个函数排队的调用,你可以保证在第二个函数启动时,第一个将完成并将你的`dont`属性设置回0. (3认同)

Mar*_*ery 6

你可以解开你的处理程序.off,但有一个警告; 如果你这样做只是阻止处理程序在它已经运行时再次被触发,你需要推迟重新绑定处理程序.

例如,考虑一下这段代码,它使用5秒热睡眠来模拟同步并且在处理程序中完成计算成本高昂的事情(比如说重型DOM操作):

<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>
Run Code Online (Sandbox Code Playgroud)

这不行.正如您所看到的,如果您在此JSFiddle中尝试它,如果在处理程序已执行时单击该按钮,则处理程序将在第一次执行完成后再次执行.更重要的是,至少在Chrome和Firefox中,即使你没有使用jQuery并使用addEventListenerremoveEventListener添加和删​​除处理程序,这也是如此.浏览器在第一次单击,解除绑定和重新绑定处理程序后执行处理程序,然后处理第二次单击并检查是否有要执行的单击处理程序.

要解决此问题,您需要延迟使用处理程序重新绑定setTimeout,以便重新附加处理程序之前处理在执行第一个处理程序时发生的单击.

<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>
Run Code Online (Sandbox Code Playgroud)

你可以在这个修改过的JSFiddle中看到这个.

当然,如果您在处理程序中执行的操作已经是异步的,那么这是不必要的,因为那时您已经控制了浏览器并让它在重新绑定处理程序之前刷新所有单击事件.例如,像这样的代码可以正常工作而无需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>
Run Code Online (Sandbox Code Playgroud)


Cha*_*ste 5

您可以像其他人一样在我告诉您之前进行操作:

A.)使用button元素的.data共享外观变量(或仅全局变量)

if ($('#buttonId').data('locked') == 1)
    return
$('#buttonId').data('locked') = 1;
// Do your thing
$('#buttonId').data('locked') = 0;
Run Code Online (Sandbox Code Playgroud)

B.)禁用鼠标信号

$("#buttonId").css("pointer-events", "none");
// Do your thing
$("#buttonId").css("pointer-events", "auto");
Run Code Online (Sandbox Code Playgroud)

C.)如果它是HTML按钮,则可以将其禁用(输入[type = submit]或按钮)

$("#buttonId").attr("disabled", "true");
// Do your thing
$("#buttonId").attr("disabled", "false");
Run Code Online (Sandbox Code Playgroud)

但是请注意其他线程!我失败了很多次,因为我的动画(淡入或淡出)花费了一秒钟。例如,fadeIn / fadeOut支持将回调函数作为第二个参数。如果没有其他方法,请使用setTimeout(callback, delay)

问候,托马斯