複数回発生するjQueryクリックイベント


283

ビデオポーカーゲームの基本を理解する方法として、JavaScriptでビデオポーカーゲームを作成しようとしています。jQueryのクリックイベントハンドラーが複数回起動するという問題に遭遇しました。

それらは賭けをするためのボタンに取り付けられており、ゲーム中に最初の手で賭けをするのにうまく機能します(1回だけ発砲します)。ただし、秒針の賭けでは、ベットまたはプレイスベットボタンが押されるたびにクリックイベントが2回発生します(そのため、1回の押すごとに2倍の正しい金額が賭けられます)。全体として、ベットボタンを1回押したときにクリックイベントが発生する回数は、このパターンに従います。シーケンスの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);要素の同じプロパティを2回以上使用する場合は、そのプロパティをキャッシュしてください。ルックアップは高価です。
デビッドはモニカを

応答、およびプロパティのキャッシュに関するヒントをありがとうございます。player.moneyとplayer.betをローカル変数moneyに設定し、その関数の内部に賭けて、代わりにそれらを操作し、残りのコードも変更してそれを行うようにします。金額の初期化が行われています。正規表現のように見えますが、簡単には理解できません。
Gregory Fowler

@GregoryFowler-あなたの質問とは無関係ですが... JavaScriptのswitchステートメントは調べてみる価値があるかもしれません。
クレイトン2014年

2
男、あなたの関数はそれが呼び出されるたびにクリックハンドラーを配置しています。各ラウンドでそれを呼び出すと、ラウンド2で2つのハンドラーが続きます。各ハンドラーがその仕事を行い、ラウンド100で100のアラートを受け取ります。
Marco Faustinelli、2015年

これは、コードのどこかで、最初にバインドを解除せずにイベントハンドラーを再バインドしているために発生します。同様のシナリオと適切な説明については、この質問を参照してください。
jpaugh 2017年

回答:


526

クリックのみのアクションを確認するには、これを使用します。

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

31
はい、ロブ、昨日どこにいましたか?;)それがまさに私が探していたものです。なぜそれを以前に見つけられなかったのか分かりません。しかし、私は他の多くのことを学んだので、それはまだ変装の祝福でした。
Gregory Fowler

1
;) ごめんなさい。私もこれで数日間車輪を回しました。そもそもなぜそれが起こるのかという論理的な理由を探しています。
Rob

6
非常に多くのことをした後の人間 私の場合を除いて、同等のものを使用しました:$( "
。bet

7
jroi_webが以下に述べるように、このメソッドは非推奨です。より最近の解決策については、@ trolleの回答を参照してください。
Pascal

クリックハンドラーは1回限りの使い捨てではありません。特に質問で示されたかさばるif-if-ifの場合は特にそうです。あなたはそれを添付し、ページが存続している限りそれを機能させることになっています。
Marco Faustinelli、2015年

378

.unbind()は非推奨であり、.off()代わりにメソッドを使用する必要があります。電話をかける.off()直前に電話するだけです.on()

これにより、すべてのイベントハンドラーが削除されます。

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

登録された「クリック」イベントハンドラのみを削除するには:

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

9
unbind

魅力的な作品!私の関数はクリックで1回実行され、次に2回、4回実行されます... .on()がこの問題を解決する前に.off()が実行されます。
jumpOnCommand

146

。1()

より良いオプションは.one()

ハンドラーは、イベントタイプごとに要素ごとに最大1回実行されます。

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

複数のクラスがあり、各クラスを1回クリックする必要がある場合は、

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

8
あなたは複数持っている場合、それがために最良の答えは、あなたは愚かなハックから私を救った、これははるかに優れているonclick同じ要素にイベントを、異なる場所で、これは他の部分には影響しません、しながら、unbind()そしてoff()ちょうど他の破壊するonclickのをもう一度お願いします
Fanckush

3
すべての答えを試した後、これは私にとって唯一の作品です。
ノーション2015年

10
注意すべき点の1つは、関数をPER CLICKごとに1回だけ起動し、その後のクリックで引き続き起動する場合、ページの存続期間中、文字通り1回だけ起動します。したがって、off()。on()メソッドを使用したmtlの回答を使用する必要があります。
Derek Hewitt

1
@munchschair、これには複数の理由が考えられます。互いに同じクラスを持つ複数の要素。または、クリックハンドラーが反復で複数回登録されています。
Shaunak D 2016

3
IDを持つボタン要素が1つしかなく、トラップされるイベント(クリックイベント)が1つしかないため、私にとっては機能しません。これはjQueryのバグだと思いましたが、おそらくBootstrapのモーダルダイアログのバグでしょう。
MC9000

78

それでも.off().unbind()または.stopPropagation()で特定の問題が解決されない場合は、.stopImmediatePropagation()を使用してみてください。すでに処理されている他のイベントに影響を与えます。何かのようなもの:

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

トリックを行います!


これは、イベントの2度の発射を止めるのと同様に私を助けましたが、同時に私を大混乱させました。jQuery UI Dialogフィールドにアタッチされたイベントハンドラーでevent.stopImmediatePropagation()を使用すると、何らかの理由で、ダイアログがグローバル変数の最新のインスタンスを参照できなくなり、代わりにグローバル変数のバージョンを使用することが判明しましたjQuery UI Dialogレンダリングの前。つまり、たとえば、jQuery UI Dialogのレンダリング時にグローバル変数が宣言されていても初期化されていない場合、初期化されていないjQuery UI Dialogイベントハンドラーとして表示されます
UkraineTrain

1
または、jQuery UI Dialogをレンダリングする前に何らかのグローバル変数に値16を割り当てた場合(後で55に変更された場合など)、その時点でも、jQuery UI Dialogイベントハンドラーでそのグローバル変数に16が表示されます。 16ではありません。そのため、人々が知っておくべきjQuery UIバグのように見えます。
UkraineTrain 2015

説明するのが難しい非常に特殊な状況の場合。それはあなたが言ったとおりに機能します:「他のイベントに影響を与えずに機能します」。ありがとうございました!:)
Toms Bugna、2016年

私にとってはまったく問題なく動作します。ありがとう!
Somnath Pawar 2017年

18

あなたがそれぞれにその関数を呼び出している場合、それはだ、「クリック」の追加、各コールのハンドラの別のペアを。

jQueryでハンドラーを追加することは、「onclick」属性の値を設定することとは異なります。ハンドラは好きなだけ追加できます。


4
あなたの答えは私を正しい方向に導き、私は多くを学びましたが、残念ながらjQueryを使用して私の問題を解決するのに十分ではありません。:) on / off、live(およびdelegate)/ die、1つを使用してから、addEventListener / removeEventListenerを使用してみましたが、できる限りのことは、ハンドラーの指数関数的成長を遅くすることでした。結局、とりあえずonclickの問題を解決しました。しかし、私はあなたの答えからキャプチャ/バブリングのようなJavaScriptのイベントモデルについて多くのことを学んだので、感謝しています。ありがとうございました。:)
グレゴリーファウラー

どうもありがとう、知らなかったなんて信じられない!
レニー

12

イベントが複数回登録されると(同じハンドラーであっても)、複数回発生します。

たとえば$("ctrl").on('click', somefunction)、ページが部分的に更新されるたびにこのコードが実行されると、イベントも毎回登録されます。したがって、ctrlが1回だけクリックされた場合でも、「somefunction」が複数回実行される可能性があります。実行される回数は、登録された回数によって異なります。

これは、JavaScriptに登録されたすべてのイベントに当てはまります。

解決:

「on」を1回だけ呼び出すようにしてください。

何らかの理由でアーキテクチャを制御できない場合は、次のようにします。

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


あなたが本当に言いたいことは?
Somnath Kharat 2015

これは、この場合に何が起こっているかを説明しません。ボタンには、一意のIDが1つとイベントが1つしかありません(ボタンは1回しかクリックできないため、複数回呼び出されることはありません)。これは、jQueryダイアログボックスにのみ表示されるバグです(再現も非常に簡単です)。
MC9000 2016年

2
関数「pushingBetButtons」が1回だけ呼び出されるのか、それとも複数回呼び出されるのかはわかりません。複数回呼び出される場合は、イベントが複数回登録されるため、ボタンが1回クリックされた場合でも、複数回起動されます。 。
Kalpesh Popat 2017年

4

マークアップが原因で問題が発生しました。

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

同じクラス「myclass」がhtmlに2回あることに気づいたので、divの各インスタンスに対してクリックを呼び出します。


3

より良いオプションはオフを使用することです

<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 2017年

2

これは、特定のイベントが同じ要素に複数回バインドされているために発生します。

私のために働いた解決策は:

.die()メソッドを使用して添付されたすべてのイベントを強制終了します。

次に、メソッドリスナーをアタッチします。

したがって、

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

でなければなりません:

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

2

stopPropagation()クリックを回避するには、イベントが何度もトリガーされる必要があります。

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

これは、イベントがDOMツリーを泡立たせないようにし、親ハンドラーにイベントが通知されないようにします。このメソッドは引数を受け入れません。

event.isPropagationStopped()このメソッドが(そのイベントオブジェクトで)呼び出されたかどうかを判断するために使用できます。

このメソッドは、trigger()でトリガーされたカスタムイベントでも機能します。これにより、同じ要素の他のハンドラーの実行が妨げられることはありません。


2

私の場合、「デリゲート」を使用していたため、これらのソリューションはどれも機能しませんでした。マルチクリックの問題を引き起こしていたのは、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)
})



1

.oneは、ページの存続期間中に1回だけ発生します

したがって、検証を実行したい場合、これは適切なソリューションではありません。検証後にページを離れない場合、戻ってくることは決してないからです。使用する方が良い

$(".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

私がこの問題に対処するとき、私は常に以下を使用します:

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

このようにして、同じストロークでバインド解除と再バインドを行います。


0

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

イベントが常に1回だけ発生するようにするには、Jquery .one()を使用できます。jQuery oneは、イベントハンドラーが1回だけ呼び出されるようにします。さらに、現在のクリック操作の処理が完了したときに、イベントハンドラーをサブスクライブして、さらにクリックを許可することができます。

<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

その方法を試してください:

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

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

私の場合*.js、ページ内の同じファイルを<script>タグで2回ロードしたため、両方のファイルが要素にイベントハンドラーをアタッチしていました。重複した宣言を削除し、問題を修正しました。


0

私が見つけた別の解決策は、複数のクラスがあり、ラベルをクリックしながらラジオボタンを処理している場合です。

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

0

動的に生成されたリンクでこの問題が発生していました:

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

私は問題document'body'修正してに置き換えることがわかりました:

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


0

バインド解除()は機能しますが、将来的に他の問題が発生する可能性があります。ハンドラーは別のハンドラーの内部にあるときに複数回トリガーされるため、ハンドラーを外部に保持し、ネストされたハンドラーの値が必要な場合は、ハンドラーがアクセスできるグローバル変数に値を割り当てます。



-1

以下のコードは、チャットアプリケーションで複数のマウスクリックトリガーイベントを2回以上処理するために機能しました。 if (!e.originalEvent.detail || e.originalEvent.detail == 1) { // Your code logic }

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.