如何临时禁用jQuery中的点击处理程序?


67

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

$("#button_id").click(function() {
  //disable click event
  //do something
  //re-enable click event
}

如何临时禁用按钮的click事件,直到原始单击的处理结束?单击按钮后,基本上可以使div消失,但是如果用户快速单击按钮几次,它将在div消失之前处理所有这些单击。我想对按钮进行“反跳”操作,以便在div消失之前只有第一次单击被注册。



Answers:


71

我注意到这篇文章很旧,但它出现在Google的顶部,并且从未提供过这种解决方案,所以我还是决定将其发布。

您可以只禁用光标事件,稍后再通过CSS再次启用它们。所有主流浏览器均支持该功能,在某些情况下可能会有用。

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

   $("#button_id").css("pointer-events", "none");
   //do something
   $("#button_id").css("pointer-events", "auto");
}

从理论上讲,这是一个很好的解决方案,但并没有得到普遍支持:IE支持仅从版本11开始。这意味着当前仍存在许多浏览器,您需要为其寻找其他解决方案。
C.Champagne 2014年

如果仍然需要对旧版IE的支持,有很简单的方法可以解决此问题(可以在wp8 HTML5移动应用程序中使用上面的代码,而在7中则不能使用)。在较旧的版本中,我建议使用此方法修复它Vinylfox.com/forwarding-mouse-events-through-layers
Defain 2014年

-1; 像这里的其他几个答案一样,这是行不通的,因为在考虑是否为下一次单击执行处理程序之前,您将同步禁用指针事件,执行其余处理程序并重新启用指针事件。至少在Chrome(但实际上可能在所有浏览器中)中,这将与没有.css()调用的同一代码完全相同。有关演示,请参见jsfiddle.net/at75H/16;打开控制台,单击按钮多次,然后观察到即使禁用了指针事件,该处理程序也连续运行多次。
Mark Amery

1
这不适用于以编程方式单击的按钮。
控制论

这对于临时用例来说是完美的选择,因为您无需重新启用点击就可以立即启用点击。只需将其设置回自动就可以了。
文森特

37

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

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

function DoSomething() {
  // do something.

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

一个只会执行一次(直到再次连接)。此处提供更多信息:http : //docs.jquery.com/Events/one


1
-1; 这行不通。例如,尝试在此小提琴中多次快速单击按钮:jsfiddle.net/at75H/1
Mark Amery

@MarkAmery:不是因为您要在回调内重新附加处理程序?如果您不这样做,它将按预期工作:jsfiddle.net/at75H/2
Dave Ward

1
您将答案中的处理程序重新附加到您的答案中,而我的提琴正是基于此。您需要在某个时候重新连接它,否则您将永久禁用该处理程序,而不是暂时禁用它。我认为这里的干净解决方案是使用0mssetTimeout调用推迟处理程序的重新连接-如果有机会,我会为此写一个答案。
Mark Amery 2014年

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

请记住,$。data()仅适用于ID为ID的项目。


我比.one选项更喜欢此解决方案。我一直在处理可能观察不到一个事件的元素。通过使用.one或再次调用.off和.on,我将更改回调的顺序。通过添加回调函数可以观察到的数据属性,您可以保持回调顺序完整
mikeweber 2012年

3
您早日返回这里绝对不会生效。JavaScript是单线程的,因此如果有几个调用该函数排队,你可以保证的时候,第二个启动后,首先将完成,并设置你的dont属性回到0
马克·阿梅里奥

7

您可以将您的处理程序与解除绑定.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>

这行不通。如您所见,如果您在此JSFiddle中进行了尝试,如果在处理程序已经执行时单击该按钮,则在第一次执行完成后,处理程序将再次执行。更重要的是,至少在Chrome和Firefox,这会即使您没有使用jQuery和使用是真实的addEventListener,并removeEventListener添加和删除处理程序来代替。浏览器在第一次单击后执行处理程序,解除绑定并重新绑定处理程序,然后处理第二次单击并检查是否有要执行的单击处理程序。

要解决此问题,您需要使用延迟处理程序的重新绑定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>

您可以在此经过修改的JSFiddle中看到这一点

自然,如果您在处理程序中正在执行的操作已经是异步的,则这是不必要的,因为那样您就已经将控制权交给了浏览器,并让它在重新绑定处理程序之前刷新了所有click事件。例如,这样的代码无需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>

这次真是万分感谢。在过去的几天里,我遇到了这个确切的问题,我需要暂时解除对我们正在使用的焦点事件的绑定。
唐纳德·马西森

谢谢!我有一个稍微不同的用例,但是使用setTimeout允许函数在重新附加点击处理程序之前退出。经过数小时的故障排除,这为我节省了时间。
mags

5

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

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

if ($('#buttonId').data('locked') == 1)
    return
$('#buttonId').data('locked') = 1;
// Do your thing
$('#buttonId').data('locked') = 0;

B.)禁用鼠标信号

$("#buttonId").css("pointer-events", "none");
// Do your thing
$("#buttonId").css("pointer-events", "auto");

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

$("#buttonId").attr("disabled", "true");
// Do your thing
$("#buttonId").attr("disabled", "false");

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

问候,托马斯


1
在浏览器中执行的JavaScript是单线程的;我不知道“当心其他线程”是什么意思,但是我敢肯定您误会了正在发生的事情。
Mark Amery

1
指针事件是去链接的方式,但兼容性只到IE 11
亚历山大尼

3

如果#button_id表示标准的HTML按钮(如提交按钮),则可以使用'disabled'属性使该按钮对浏览器无效。

$("#button_id").click(function() {
    $('#button_id').attr('disabled', 'true');

    //do something

     $('#button_id').removeAttr('disabled');
});   

但是,您可能需要注意的是这些事情发生的顺序。如果使用的是jquery hide命令,则可能要包括“ $('#button_id')。removeAttr('disabled');” 作为回叫的一部分,以便在隐藏完成之前不会发生。

[使用回调函数的示例]:

$("#button_id").click(function() {
    $('#button_id').attr('disabled', 'true');
    $('#myDiv').hide(function() { $('#button_id').removeAttr('disabled'); });
});   

像这里的大多数答案一样,此答案(或至少是第一个代码示例)有缺陷:您的第一个示例在浏览器考虑如何处理下一次单击之前同步禁用按钮,执行处理程序并重新启用按钮。有关此失败的演示,请参见jsfiddle.net/at75H/18。如果您打开控制台并多次单击该按钮,则尽管添加了该属性,您也会看到处理程序多次触发。您需要推迟删除该属性(例如,使用),以使其起作用。disabledsetTimeout
Mark Amery

0

尝试利用 .one()

var button = $("#button"),
  result = $("#result"),
  buttonHandler = function buttonHandler(e) {
    result.html("processing...");
    $(this).fadeOut(1000, function() {
      // do stuff
      setTimeout(function() {
        // reset `click` event at `button`
        button.fadeIn({
          duration: 500,
          start: function() {
            result.html("done at " + $.now());
          }
        }).one("click", buttonHandler);

      }, 5000)
    })
  };

button.one("click", buttonHandler);
#button {
  width: 50px;
  height: 50px;
  background: olive;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<div id="result"></div>
<div id="button">click</div>


几乎为此加了-1,但也许我太苛刻了。与大多数答案不同,此方法有效(因为您延迟使用来读取处理程序setTimeout),但是没有任何说明。如果我还不了解推迟阅读处理程序的必要性,我觉得这对我没有用。
马克·阿默里

@MarkAmery几乎为此setTimeout付出了-1,但也许我太苛刻了。与大多数答案不同,此方法有效(因为您延迟使用来读取处理程序),但没有说明发生了什么实际的方法是利用.one()setTimeout.fadeOut().fadeIn()分别使用的示范目的.one()。也就是说,事件最多只能调用一次;.one()当所有同步或异步过程完成时使用re-attach事件。如果button在任务完成之前发生点击,则不会附加任何事件;事件已附加,一次又重新附加一次
guest271314 '16

0

最好使用当前事件,不要在全局处理程序中保存处理程序。我得到当前元素事件,然后取消绑定,然后再次绑定。对于处理程序。

var element =  $("#elemid")[0];
var tempHandler = jQuery._data(element)["events"]["click"][0].handler;
$("#elemid").unbind("click");

// do the job that click not suppose to listen;
$("#elemid").bind("click" , tempHandler );

对于所有处理程序

var element =  $("#elemid")[0];
var clickHandlerList = jQuery._data(element)["events"]["click"];
var handlerList = [];
for(var i  = 0 ; i <  clickHandlerList .length ; i++) {
    handlerList .push(clickHandlerList [i].handler);
}
$("#elemid").unbind("click");
// do the job that click not suppose to listen;
for(var i  = 0 ; i <  handlerList.length ; i++) {
    // return back all handler to element.
    $("#elemid").bind("click" , handlerList[i]);
}

0

我在等待函数完成时尝试显示加载微调器时,几乎没有遇到这个问题。因为我将微调器附加到HTML,所以每次单击按钮时都会复制微调器,如果您不反对在全局范围内定义变量,那么这对我来说效果很好。

    var hasCardButtonBeenClicked = '';
    $(".js-mela-card-button").on("click", function(){  
        if(!hasCardButtonBeenClicked){
            hasCardButtonBeenClicked = true;
            $(this).append('<i class="fa fa-circle-o-notch fa-spin" style="margin-left: 3px; font-size: 15px;" aria-hidden="true"></i>');
        }    
    });

注意,我要做的就是声明一个变量,只要它的值为null,就会发生单击后的动作,然后将变量的值设置为“ true”(可以是任何值,只要它是(不为空),请进一步禁用该按钮,直到刷新浏览器或将该变量设置为null为止。

回顾一下,将hasCardButtonBeenClicked变量设置为“ false”可能会更有意义,然后根据需要在“ true”和“ false”之间交替。


-1

此示例工作。


HTML代码:

  <div class="wrapper">
     <div class="mask">Something</div> 
  </div>

jQuery的:

    var fade = function(){
        $(".mask").fadeToggle(500,function(){
            $(this).parent().on("click",function(){
                $(this).off("click");
                fade();
            });
        });
    };

    $(".wrapper").on("click",function(){
        $(this).off("click");
        fade();     
    });

-2
$("#button_id").click(function() {
    $('#button_id').attr('disabled', 'true');
    $('#myDiv').hide(function() { $('#button_id').removeAttr('disabled'); });
}); 

不要使用.attr()来做残疾人,使用.prop()会更好。


-2

此代码将在按钮标签上显示加载,并将按钮设置为禁用状态,然后在处理之后,重新启用并返回原始按钮文本:

$(function () {

        $(".btn-Loading").each(function (idx, elm) {
            $(elm).click(function () {
                //do processing
                if ($(".input-validation-error").length > 0)
                    return;
                $(this).attr("label", $(this).text()).text("loading ....");
                $(this).delay(1000).animate({ disabled: true }, 1000, function () {
                    //original event call
                    $.when($(elm).delay(1000).one("click")).done(function () {
                        $(this).animate({ disabled: false }, 1000, function () {
                            $(this).text($(this).attr("label"));
                        })
                    });
                    //processing finalized
                });
            });
        });
        // and fire it after definition
    }
   );
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.