jQuery单击事件多次触发

Posted

技术标签:

【中文标题】jQuery单击事件多次触发【英文标题】:jQuery click events firing multiple times 【发布时间】:2013-02-04 20:53:24 【问题描述】:

我正在尝试用 javascript 编写一个视频扑克游戏,以了解它的基础知识,但我遇到了一个问题,即 jQuery click 事件处理程序多次触发。

它们附在用于下注的按钮上,在游戏过程中第一手下注时效果很好(仅触发一次);但是在下注秒手时,每次按下下注或下注按钮时,它都会触发两次点击事件(因此每次按下正确的金额都会下注两次)。总的来说,当按下一个投注按钮一次时,点击事件被触发的次数遵循这种模式——其中序列的 ​​ith 项是针对 ith 游戏开始时的手牌:1, 2, 4, 7, 11, 16, 22, 29, 37, 46,无论值多少,这似乎是 n(n+1)/2 + 1——并且我不够聪明,无法弄清楚,我使用了OEIS。 :)

这是带有正在执行的单击事件处理程序的函数;希望它很容易理解(如果没有,请告诉我,我也想在这方面做得更好):

/** The following function keeps track of bet buttons that are pressed, until place button is pressed to place bet. **/
function pushingBetButtons() 
    $("#money").text("Money left: $" + player.money); // displays money player has left

    $(".bet").click(function() 
        var amount = 0; // holds the amount of money the player bet on this click
        if($(this).attr("id") == "bet1")  // the player just bet $1
            amount = 1;
         else if($(this).attr("id") == "bet5")  // etc.
            amount = 5;
         else if($(this).attr("id") == "bet25") 
            amount = 25;
         else if($(this).attr("id") == "bet100") 
            amount = 100;
         else if($(this).attr("id") == "bet500") 
            amount = 500;
         else if($(this).attr("id") == "bet1000") 
            amount = 1000;
        
        if(player.money >= amount)  // check whether the player has this much to bet
            player.bet += amount; // add what was just bet by clicking that button to the total bet on this hand
            player.money -= amount; // and, of course, subtract it from player's current pot
            $("#money").text("Money left: $" + player.money); // then redisplay what the player has left
         else 
            alert("You don't have $" + amount + " to bet.");
        
    );

    $("#place").click(function() 
        if(player.bet == 0)  // player didn't bet anything on this hand
            alert("Please place a bet first.");
         else 
            $("#card_para").css("display", "block"); // now show the cards
            $(".card").bind("click", cardClicked); // and set up the event handler for the cards
            $("#bet_buttons_para").css("display", "none"); // hide the bet buttons and place bet button
            $("#redraw").css("display", "block"); // and reshow the button for redrawing the hand
            player.bet = 0; // reset the bet for betting on the next hand
            drawNewHand(); // draw the cards
        
    );

如果您有任何想法或建议,或者我的问题的解决方案是否与此处的另一个问题的解决方案相似,请告诉我(我查看了许多类似标题的线程,但没有找到解决方案这可能对我有用)。

【问题讨论】:

var amount = parseInt(this.id.replace(/[^\d]/g,''),10); 如果您要多次缓存该属性,请不要一直查找它。查找费用很高。 感谢您的回复,以及关于缓存属性的提示。我将 player.money 和 player.bet 设置为局部变量 money 并在该函数中下注并操作它们,并将更改我的其余代码也这样做。:) 如果你有时间,你能否解释一下你的建议金额的初始化正在做;它看起来像一些正则表达式,但我不能轻易理解它。 @GregoryFowler - 与您的问题无关,但是... javascript switch 语句可能值得研究。 伙计,您的函数在每次调用时都会放置一个点击处理程序。如果你在每一轮调用它,在第二轮你有两个处理程序,依此类推。每个处理程序都完成其工作,在第 100 轮时您会收到 100 个警报。 发生这种情况是因为在代码中的某处,您重新绑定了事件处理程序,而没有先解除绑定。请参阅此问题以获取 similar scenario 和一个很好的解释。 【参考方案1】:

为了确保一次点击只操作一次使用这个:

$(".bet").unbind().click(function() 
    //Stuff
);

【讨论】:

好的,Rob,你昨天在哪里? ;) 这正是我一直在寻找的,不知道为什么我以前没有找到它。但这仍然是因祸得福,因为我确实学到了很多其他东西。 ;) 抱歉。我也在这个上旋转了几天。我仍在寻找一个合乎逻辑的原因来解释为什么它会首先发生。 在做了这么多事情之后,它做到了。除了在我的情况下,我使用了相当于: $(".bet").off().on() 正如 jroi_web 下面所说,此方法已被弃用。有关更新的解决方案,请参阅 @trolle 的答案。 点击处理程序不是一次性的东西。特别是当它是问题中显示的庞大的 if-if-if 时。只要页面存在,您就应该附加它并让它发挥作用。【参考方案2】:

.unbind() 已弃用,您应该改用.off() 方法。只需在致电 .on() 之前致电 .off()

这将删除所有事件处理程序:

$(element).off().on('click', function() 
    // function body
);

仅删除已注册的“点击”事件处理程序:

$(element).off('click').on('click', function() 
    // function body
);

【讨论】:

这应该在较新版本的 jQuery 中使用,因为 unbind, die or live 已经被弃用了 像魅力一样工作!我的函数会在点击时运行一次,然后运行两次,四次...... .off() 在 .on() 解决这个问题之前。【参考方案3】:

.one()

.one() 是更好的选择:

每个事件类型的每个元素最多执行一次处理程序。

$(".bet").one('click',function() 
    //Your function
);

如果有多个类,每个类都需要点击一次,

$(".bet").on('click',function() 
    //Your function
    $(this).off('click');   //or $(this).unbind()
);

【讨论】:

最佳答案,你把我从一个愚蠢的黑客中救了出来,这要好得多,因为如果你有多个 onclick 事件到同一个元素但在不同的位置,这不会影响其余的,而 @ 987654327@ 和 off() 只会摧毁其他 onclicks 再次感谢您 在尝试了所有答案之后,这一个是我唯一的工作。 有一点需要注意,如果您希望函数每次点击只触发一次,但在后续点击时继续触发,那么这个函数在页面的整个生命周期内只会触发一次。所以需要使用mtl的off().on()方法回答。 @munchschair,这可能有多种原因。彼此内部具有相同类的多个元素。或者在一次迭代中多次注册点击处理程序。 不适合我 - 仍然多次点击触发 - 没有意义,因为只有 1 个带有 ID 的按钮元素并且只有 1 个事件被捕获(点击事件)。我认为这是一个 jQuery 错误,但它可能是一个 Bootstrap 模式对话框错误。【参考方案4】:

如果您发现 .off() .unbind() 或 .stopPropagation() 仍然无法解决您的特定问题,请尝试使用 .stopImmediatePropagation() 在您只想处理事件而不会冒泡的情况下效果很好并且不影响已经处理的任何其他事件。比如:

$(".bet").click(function(event) 
  event.stopImmediatePropagation();
  //Do Stuff
);

成功了!

【讨论】:

这帮助了我以及阻止事件触发两次,但也让我大吃一惊。事实证明,如果您在附加到 jQuery UI 对话框字段的事件处理程序中使用 event.stopImmediatePropagation(),那么,由于某种原因,对话框不能再引用全局变量的最新实例,而是使用全局变量的版本在 jQuery UI 对话框渲染之前。这意味着,例如,如果您的全局变量已声明,但在 jQuery UI 对话框呈现时未初始化,那么它将显示为未初始化的 jQuery UI 对话框事件处理程序 或者如果您在渲染 jQuery UI 对话框之前为某个全局变量分配了 16 的值,后来更改为 55,那么 16 将在 jQuery UI 对话框事件中显示为该全局变量处理程序,即使那时它不再是 16。所以,它看起来像一个人们应该注意的 jQuery UI 错误。 对于非常具体的情况,甚至难以描述。它完全按照您所说的那样工作:“在不影响任何其他事件的情况下工作”。谢谢! :) 对我来说完全没问题。谢谢! 我去了超过15个答案,终于找到了这个e.stopImmediatePropagation【参考方案5】:

如果您在每次“点击”时调用该函数,那么它就是在每次调用时添加另一对处理程序。

使用 jQuery 添加处理程序与设置“onclick”属性的值不同。可以根据需要添加任意数量的处理程序。

【讨论】:

您的回答让我朝着正确的方向前进,我学到了很多东西,但不幸的是还不足以解决我使用 jQuery 的问题。 :) 我尝试使用 on/off、live(和 delegate)/die 和一个,然后 addEventListener/removeEventListener,但我能做的最好的事情就是减缓处理程序的指数增长。我最终暂时用 onclick 解决了我的问题。但是我仍然从你的回答中学到了很多关于 Javascript 的事件模型,比如捕获/冒泡,所以我很感激。谢谢你。 :) 非常感谢,我不敢相信我不知道这个!【参考方案6】:

一个事件在被多次注册时会触发多次(即使是同一个处理程序)。

例如$("ctrl").on('click', somefunction) 如果每次页面部分刷新时都执行这段代码,则每次都注册事件。因此,即使 ctrl 仅被单击一次,它也可能多次执行“somefunction” - 它执行多少次将取决于它被注册的次数。

这适用于任何在 javascript 中注册的事件。

解决方案:

确保只调用一次“on”。

由于某种原因,如果您无法控制架构,请执行以下操作:

$("ctrl").off('click'); $("ctrl").on('click', somefunction);

【讨论】:

你真正想说什么? 这并不能解释在这种情况下发生了什么。该按钮有一个唯一的 ID 和只有 1 个事件(它不会被多次调用,因为它只能被单击一次)。这是一个只出现在 jQuery 对话框中的错误(而且很容易重现)。 我们不知道函数“pushingBetButtons”是只被调用一次还是被多次调用。如果它被多次调用,则事件被注册多次,因此它也会被多次触发。 .即使按钮被点击一次。【参考方案7】:
$('.bed').one(function() )

文档:

http://api.jquery.com/one/

【讨论】:

【参考方案8】:

我们必须stopPropagation()以避免Clicks触发事件的次数过多。

$(this).find('#cameraImageView').on('click', function(evt) 
   evt.stopPropagation();
   console.log("Camera click event.");
);

它防止事件在 DOM 树中冒泡,防止任何父处理程序收到事件通知。此方法不接受任何参数。

我们可以使用event.isPropagationStopped() 来确定是否曾经调用过这个方法(在那个事件对象上)。

此方法也适用于使用 trigger() 触发的自定义事件。请注意,这不会阻止同一元素上的其他处理程序运行。

【讨论】:

【参考方案9】:

由于标记,我遇到了问题。

html

<div class="myclass">
 <div class="inner">

  <div class="myclass">
   <a href="#">Click Me</a>
  </div>

 </div>
</div>

jQuery

$('.myclass').on('click', 'a', function(event)  ...  );

您注意到我在 html 中有两次相同的类“myclass”,因此它为每个 div 实例调用 click。

【讨论】:

【参考方案10】:

当我处理这个问题时,我总是使用:

$(".bet").unbind("click").bind("click", function (e) 
  // code goes here

这样我在同一笔划中解绑和重新绑定。

【讨论】:

【参考方案11】:

更好的选择是使用off

<script>
function flash() 
  $("div").show().fadeOut("slow");

$("#bind").click(function() 
  $( "body" )
    .on("click", "#theone", flash)
    .find("#theone")
      .text("Can Click!");
);
$("#unbind").click(function() 
  $("body")
    .off("click", "#theone", flash)
    .find("#theone")
      .text("Does nothing...");
);
</script>

【讨论】:

【参考方案12】:

所有关于 .on() 和 .one() 的东西都很棒,jquery 也很棒。

但有时,您希望用户无法点击的情况更加明显,在这种情况下,您可以执行以下操作:

function funName()
    $("#orderButton").prop("disabled", true);
    //  do a bunch of stuff
    // and now that you're all done
    setTimeout(function()
        $("#orderButton").prop("disabled",false);
        $("#orderButton").blur();
    , 3000);

你的按钮看起来像:

<button onclick='funName()'>Click here</button>

【讨论】:

这将解决用户实际点击多次的情况,但是......我收到了多个具有相同时间戳的点击事件。我不可能在同一毫秒内点击 3 次,即使我 非常 很快(并且不知何故不知道我按下了多少次按钮)。【参考方案13】:

这是因为特定事件多次绑定到同一个元素。

对我有用的解决方案是:

使用.die()方法杀死所有附加的事件。

然后附加你的方法监听器。

因此,

$('.arrow').click(function() 
// FUNCTION BODY HERE

应该是:

$('.arrow').die("click")
$('.arrow').click(function() 
// FUNCTION BODY HERE

【讨论】:

【参考方案14】:

就我而言,我使用的是“委托”,所以这些解决方案都不起作用。我相信是通过ajax调用多次出现的按钮导致了多次点击问题。解决方案使用了超时,因此只能识别最后一次点击:

var t;
$('body').delegate( '.mybutton', 'click', function()
    // clear the timeout
    clearTimeout(t);
    // Delay the actionable script by 500ms
    t = setTimeout( function()
        // do something here
    ,500)
)

【讨论】:

【参考方案15】:
$(element).click(function (e)

  if(e.timeStamp !== 0) // This will prevent event triggering more then once
   
      //do your stuff
   

【讨论】:

【参考方案16】:

.one 在页面的整个生命周期内只触发一次

因此,如果您想进行验证,这不是正确的解决方案,因为当您在验证后不离开页面时,您将永远不会回来。更好用

$(".bet").on('click',function() 
 //validation 
   if (validated)  
      $(".bet").off('click'); //prevent to fire again when we are not yet off the page
      //go somewhere
    
);

【讨论】:

【参考方案17】:

我在使用动态生成的链接时遇到了这个问题:

$(document).on('click', '#mylink', function(...do stuff...);

我发现用'body' 替换document 为我解决了这个问题:

$('body').on('click', '#mylink', function(...do stuff...);

【讨论】:

【参考方案18】:

https://jsfiddle.net/0vgchj9n/1/

要确保事件始终只触发一次,您可以使用 Jquery .one()。 JQuery one 确保您的事件处理程序只调用一次。此外,您可以为您的事件处理程序订阅一个,以便在您完成当前点击操作的处理后允许进一步点击。

<div id="testDiv">
  <button class="testClass">Test Button</button>
</div>

var subscribeClickEvent = function() $("#testDiv").one("click", ".testClass", clickHandler);;

function clickHandler() 
  //... perform the tasks  
  alert("you clicked the button");
  //... subscribe the click handler again when the processing of current click operation is complete  
  subscribeClickEvent();


subscribeClickEvent();

【讨论】:

【参考方案19】:

试试这个方法:

<a href="javascript:void(0)" onclick="this.onclick = false; fireThisFunctionOnlyOnce()"> Fire function </a>

【讨论】:

【参考方案20】:

在我的例子中,onclick 事件被触发了多次,因为我创建了一个通用事件处理程序

  `$('div').on("click", 'a[data-toggle="tab"]',function () 
        console.log("dynamic bootstrap tab clicked");
        var href = $(this).attr('href');
        window.location.hash = href;
   );`

改为

    `$('div#mainData').on("click", 'a[data-toggle="tab"]',function () 
        console.log("dynamic bootstrap tab clicked");
        var href = $(this).attr('href');
        window.location.hash = href;
    );`

并且还必须为静态和动态点击制作单独的处理程序,用于静态标签点击

    `$('a[data-toggle="tab"]').on("click",function () 
        console.log("static bootstrap tab clicked");
        var href = $(this).attr('href');
        window.location.hash = href;
    );`

【讨论】:

【参考方案21】:

在我的例子中,我在&lt;script&gt; 标记中两次在页面上加载了相同的*.js 文件,因此这两个文件都将事件处理程序附加到元素。我删除了重复的声明并解决了问题。

【讨论】:

【参考方案22】:

我发现的另一个解决方案是,如果您有多个类并且在单击标签时处理单选按钮。

$('.btn').on('click', function(e) 
    e.preventDefault();

    // Hack - Stop Double click on Radio Buttons
    if (e.target.tagName != 'INPUT') 
        // Not a input, check to see if we have a radio
        $(this).find('input').attr('checked', 'checked').change();
    
);

【讨论】:

【参考方案23】:

如果一切正常

$( "#ok" ).bind( "click", function() 
    console.log("click"); 
);

【讨论】:

【参考方案24】:

参考@Pointy答案。 如果这在循环中,可以通过执行以下操作来避免多次触发点击事件:

 $(".bet").each(function(i,item)
       $(this).on(
            click:function()
                //TRIGGERS ONES
            if(i)
              console.log(i); 
                //DO YOUR THING HERE
            
            
            
        );

);

【讨论】:

【参考方案25】:

下面的代码在我的聊天应用程序中为我工作,可以多次处理多个鼠标点击触发事件。 if (!e.originalEvent.detail || e.originalEvent.detail == 1) // Your code logic

【讨论】:

【参考方案26】:

Unbind () 有效,但将来可能会导致其他问题。处理程序在另一个处理程序内时会触发多次,因此请将您的处理程序放在外面,如果您想要嵌套处理程序的值,请将它们分配给一个全局变量,您的处理程序可以访问该变量。

【讨论】:

以上是关于jQuery单击事件多次触发的主要内容,如果未能解决你的问题,请参考以下文章

jquery为啥触发多次click事件

jquery 事件 多次绑定,多次触发,怎么清除历史绑定事件

使用 jQuery 在初始 .mousedown() 事件后防止后续触发

为啥 jQuery 选择事件侦听器会触发多次?

jquery popup中的事件被多次触发

jQuery Mobile 1.3.1 taphold 事件多次触发