如何防止在快速点击时调用en事件处理程序两次?

时间:2013-11-29 08:46:58

标签: javascript jquery event-handling

有一个按钮,当用户点击按钮时,一些数据会保存到后端。问题是当用户非常快速地点击按钮时,事件处理程序会多次执行。

这是代码

var x = 1;
$('#button').click(function() {
  // Do something
  // Save some data on network
  x++;
  console.log(x);
});

我希望当用户点击按钮一次时执行此处理程序。即使在双击或三击的情况下,也只能执行一次。我只是想避免快速点击,这个处理程序可以再次执行

我脑子里有多种解决方案,比如

  1. 定义一个全局变量,如IS_BUTTON_HANDLER_WORKING = false,当您输入处理程序时,将其设置为true,最后再将其设置为false。并检查是否真的从函数返回。

  2. 在开头拆分处理程序并在最后重新附加。

  3. 考虑到您的应用程序中有25个按钮。应该是实现这一目标的最佳方法。

    看看这个Fiddle

    解决方案

    $('#button').click(function() {
       $(this).attr('disabled', true);
      // Do something
      // Save some data on network
      $(this).removeAttr('disabled');
    });
    

    使用这个,我们确信我们的下一个处理程序只有在完全执行上一次执行时才会执行。

10 个答案:

答案 0 :(得分:12)

David Walsh有一个很棒的solution

// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
function debounce(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, args = arguments;
        var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
};

答案 1 :(得分:11)

有多种方法可以解决这个问题:

点击后,您可以disable / hide按钮:

$('#button').attr("disabled", true);

您还可以在每次点击时设置超时,以确保它不会再次执行:

var x, y = 1;

$('#button').click(function() {
  if (x) clearTimeout(x);
  x = setTimeout(function() {
     // do the work here
     y++;
     console.log(y);
     // ----------------
  }, 1000);
});

因此,每次单击该按钮时,它只会在1000 milliseconds之后实际执行代码,如果快速连续单击该按钮,则超时将被清除并重新开始。

请注意,上述内容未经测试

我个人认为禁用的解决方案是最好的,因为它向用户表明他已经点击并且正在发生某些事情,你甚至可以在按钮旁边显示一个加载器。

答案 2 :(得分:4)

根据编辑

您应该使用.one()

您可以点击功能unbind事件

var x = 1;
function myButtonClick() {

    $('#button').unbind('click');

    // Do something
    // Save some data on network
    x++;
    console.log(x);
    $('#button').bind('click', myButtonClick);
}

$('#button').bind('click', myButtonClick);

答案 3 :(得分:1)

您可以使用jQuery one()方法,如图所示here

答案 4 :(得分:1)

我正在使用下面的简单解决方案,它一直很适合我:

var x = 1;
e.handled=false;
$('#button').click(function(e) {
  if(e.handled==false){
      e.handled=true;
      // Do something
      // Save some data on network
      x++;
      console.log(x);      
  }
});

答案 5 :(得分:1)

您正在寻找this

$( "button" ).one( "click", function(evt) {
  x++;
  console.log(x);
});

或者,如果您需要一段时间间隔才能在两次有效点击之间失效。

var last, diff;
$( "button" ).click(function( event ) {
  if (last){
    diff = event.timeStamp - last;
    if (diff >= SOMEVAL){
      x++;
      console.log(x);    
    }
  }
  last = event.timeStamp;          
});

答案 6 :(得分:1)

var btn = document.querySelector('#twofuns');
btn.addEventListener('click',method1);
btn.addEventListener('click',method2);
function method2(){
  console.log("Method 2");
}
setTimeout(function(){
  btn.removeEventListener('click',method1);
},5000);
function method1(){
  console.log("Method 1");
}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>Pramod Kharade-RemoveEventListener after Interval</title>
</head>
<body>
<button id="twofuns">Click Me!</button>
</body>
</html>

您可以像上述在Java脚本中的多个侦听器中删除一个侦听器。

答案 7 :(得分:0)

尝试以下代码

var x = 1;
var fewSeconds=10; /*10 seconds*/

$('#button').click(function() {
$('#button').attr("disabled", "disabled");
  x++;
  console.log(x);
    var btn = $(this);
    btn.prop('disabled', true);
    setTimeout(function(){
        btn.prop('disabled', false);
    }, fewSeconds*1000);

});

答案 8 :(得分:0)

假设您已将事件监听器附加到按钮上,则一种方法只是从按钮上删除事件监听器,然后在需要时再附加它。
在事件侦听器函数本身中,添加以下代码:

function handleButtonClick(e){
  e.target.removeEventListener("click", handleBackButton);
}

这取决于您的设置。

答案 9 :(得分:-1)

点击按钮启动忙碌指示器并在最后返回之前停止

Function DoSomething(){
startBusyIndicator();
// perform Action //

stopBusyIndicator();
return;
}