【问题标题】:How to prevent calling of en event handler twice on fast clicks?如何防止在快速点击时两次调用 en 事件处理程序?
【发布时间】:2013-12-15 09:38:12
【问题描述】:

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

这是代码

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. 在开始时分离处理程序并在最后重新附加。

假设您的应用程序中有 25 个按钮。实现这一点的最佳方法应该是什么。

看看这个Fiddle

解决方案

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

使用它,我们可以确定只有在之前的执行完全完成后,我们的下一个处理程序才会执行。

【问题讨论】:

  • 尝试使用one('click', fn) 而不是click
  • 我不认为one 是正确的答案,因为处理程序不会再次被执行。您可能想在一段时间后再次提交包含更新数据的表单。

标签: javascript jquery event-handling


【解决方案1】:

大卫沃尔什有一个很棒的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);
    };
};

【讨论】:

  • 是的,我在发布这篇文章后很久才读到那篇文章。我正在更改已接受的答案,因为这是正确的方法。谢谢你把它带到这里!
  • 如果您希望事件立即触发并仅在特定时间后允许另一个呼叫,您似乎需要throttle,而不是debounce。
  • @K.H.你能举一个throttle的例子吗?我想这就是我要找的东西
  • 沙洛姆@RamiAlloush,试试this
【解决方案2】:

有多种处理方法:

点击后可以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之后的代码,如果快速连续点击按钮,就会清除超时重新开始。

注意以上内容未经测试

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

【讨论】:

  • 我喜欢这种禁用按钮的方法,因为它不需要我知道其他信息。 Any global variable 或 setinterval -> 让代码有点复杂。
  • 如果按钮被编程点击,这不会禁用它。
【解决方案3】:

根据编辑

你应该使用.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);

【讨论】:

    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      我正在使用下面的简单解决方案,它对我很有效:

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

      【讨论】:

        【解决方案6】:

        您正在寻找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;          
        });
        

        【讨论】:

          【解决方案7】:

          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 脚本中删除一个侦听器。

          【讨论】:

            【解决方案8】:

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

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

            这取决于您的设置。

            【讨论】:

              【解决方案9】:

              试试下面的代码

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

              【讨论】:

                【解决方案10】:

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

                Function DoSomething(){
                startBusyIndicator();
                // perform Action //
                
                stopBusyIndicator();
                return;
                }
                

                【讨论】:

                • 不,这样的问题只需要对处理程序进行去抖动或限制。您提到的 BusyIndi​​cator 是一个非常复杂的解决方案,对于某些协议甚至无法使其稳定。
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2023-03-21
                • 1970-01-01
                • 1970-01-01
                • 2013-12-20
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多