jQuery点击事件触发多次

349
我正在尝试用Javascript编写一个视频扑克游戏,以此来掌握其基础知识,但我遇到了一个问题:jQuery点击事件处理程序会多次触发。它们附加在下注按钮上,在第一局游戏中下注时可以正常工作(仅触发一次);但是在下注第二手牌时,每次按下下注或放置下注按钮都会触发两次点击事件(因此每次按下将下注两倍的正确金额)。总体而言,当只按下一次下注按钮时,它遵循以下模式触发点击事件的次数,其中序列的第i项是从游戏开始时第i个手牌的下注: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);如果您将要多次使用元素的同一属性,请缓存该属性,不要一直重新查找。这种查找是很昂贵的。 - David Thomas
谢谢您的回复,以及有关缓存属性的提示。我在该函数内将player.money和player.bet设置为本地变量money和bet,并对其进行操作,我将更改我的其余代码以执行此操作。:) 如果您有时间,还可以解释一下您建议的amount初始化是做什么的;它看起来像一些正则表达式,但我很难理解它的含义。 - Gregory Fowler
@GregoryFowler - 和你的问题无关,但是……可能值得研究一下 JavaScript 的 switch 语句。 - Clayton
2
兄弟,你的函数每次被调用都会放置一个点击处理程序。如果你在每个回合中调用它,在第二个回合中你就有两个处理程序,依此类推。每个处理程序都会执行其工作,到第100轮时你将获得100个警报。 - Marco Faustinelli
这��因为在你的代码中,某处重新绑定了事件处理程序而没有先解除绑定。请参考此问题以获取类似情况的详细说明 - jpaugh
可能是点击事件触发多次问题,如何解决?的重复问题。 - jpaugh
29个回答

3
更好的选择是使用 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>

3

所有关于 .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>

1
那会解决用户实际上点击多次的情况,但是...我得到了相同时间戳的多个点击事件。即使我非常迅速地这样做(并且不知道自己按按钮的次数),也不可能在同一毫秒内点击3次。 - jpaugh

2
在我的情况下,我使用的是“delegate”,所以这些解决方案都没有起作用。我相信是通过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)
})

2

这种情况通常是由于特定事件被多次绑定到同一元素上所导致的。

我使用的解决方案是:

使用.die()方法取消所有已连接的事件。

然后再附加您的方法侦听器。

这样就可以避免该问题的出现。

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

should be:

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

已弃用的jQuery版本1.7 仅在使用.live()注册时有效 - Bonez024

2

我曾遇到一个动态生成的链接问题:

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

我发现将document替换为'body'可以解决这个问题:

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

"Original Answer"译作"最初的回答"。


哇,感谢您发布这个。我一直在绝望地寻找为什么 $(document).on 会多次触发!为什么使用 'body' 可以解决呢?这一定是 JQuery 中的一个 bug。 - nwood21

1

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

1
$(element).click(function (e)
{
  if(e.timeStamp !== 0) // This will prevent event triggering more then once
   {
      //do your stuff
   }
}

0
在我的案例中,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;
    });`

0

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

为了确保事件只触发一次,您可以使用JQuery的.one()方法。JQuery one方法确保您的事件处理程序仅被调用一次。此外,您可以使用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();

0

参考@Pointy的答案。如果这是一个循环,可以通过像这样做来避免点击事件多次触发:

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

});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接