jQuery tıklama olayları birden çok kez tetiklenir


283

Javascript'te temel videolarını indirmenin bir yolu olarak bir video poker oyunu yazmaya çalışıyorum ve jQuery click olay işleyicilerinin birden çok kez çalıştığı bir sorunla karşılaştım.

Bahis yapmak için düğmelere bağlanırlar ve bir oyun sırasında ilk elden bir bahis koymak için iyi çalışır (sadece bir kez ateşleme); ancak ikinci el için yapılan bahislerde, bir bahis veya bahis koyma düğmesine her basıldığında tıklama etkinliğini iki kez tetikler (böylece her bir basış için doğru miktarın iki katı bahis yapılır). Genel olarak, bir bahis düğmesine bir kez basıldığında tıklama olayının kaç kez tetiklendiğini izler - dizinin dördüncü terimi oyunun başlangıcından i'inci elin bahsi içindir : 1, 2, 4 , 7, 11, 16, 22, 29, 37, 46, bu değer ne olursa olsun n (n + 1) / 2 + 1 gibi görünüyor - ve bunu anlamaya yetecek kadar akıllı değildim, OEIS kullandım . :)

İşte, tıklama olay işleyicileriyle çalışan işlev; umarım anlaşılması kolaydır (değilse bana bildirin, bu konuda daha iyi olmak istiyorum):

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

Herhangi bir fikriniz veya öneriniz varsa veya sorunumun çözümü burada başka bir soruna bir çözümle benziyorsa lütfen bana bildirin (benzer başlıklara çok benzedim ve çalışabilecek bir çözüm bulmakta şansım olmadı. benim için).


var amount = parseInt(this.id.replace(/[^\d]/g,''),10);Ve bir öğenin aynı özelliğini birden fazla kez kullanacaksanız, bu özelliği önbelleğe almayın . Arama pahalıdır.
David, Monica

Yanıt ve önbellek özelliklerinin ipucu için teşekkür ederiz. Player.money ve player.bet'i yerel değişkenlere para olarak ayarladım ve bu işlevin içinde bahse girdim ve bunun yerine manipüle ettim ve bunu yapmak için kodumun geri kalanını da değiştireceğim. :) Zamanınız varsa, önerilerinizi de açıklayabilir misiniz? miktarın başlatılması yapıyor; düzenli bir ifadeye benziyor, ama bunu kolayca anlayamıyorum.
Gregory Fowler

@GregoryFowler - sorunuzla ilgisi yok, ancak ... bir javascript geçiş ifadesi incelenmeye değer olabilir.
Clayton

2
Dostum, fonksiyonunuz her çağrıldığında bir tıklama işleyici yerleştiriyor. Her turda çağırırsanız, ikinci turda iki işleyiciniz var vb. Her işleyici işini yapar ve 100. turda 100 uyarı alırsınız.
Marco Faustinelli

Bunun nedeni, kodunuzun herhangi bir yerinde, olay işleyicisini önce bağlamadan yeniden bağlamanızdır. Benzer bir senaryo ve iyi bir açıklama için bu soruya bakın .
jpaugh

Yanıtlar:


526

Yalnızca bir kez yapılan tıklama işlemlerinin bunu kullandığından emin olmak için:

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

31
Tamam, dün neredeydin Rob? ;) Tam da aradığım şey buydu, neden daha önce bulamadığımı bilmiyorum. Ama yine de kılık değiştirmiş bir nimetti çünkü başka birçok şey öğrendim.
Gregory Fowler

1
;) afedersiniz. Ben de tekerleklerimi birkaç gün buralarda döndürdüm. Hala neden ilk etapta bile gerçekleştiğine dair mantıklı bir neden arıyorum.
Rob

6
Birçok şeyden sonra dostum bunu yaptı. Benim durumum dışında ben eşdeğer kullanılır: $ (".
Bet

7
Jroi_web'ın aşağıda söylediği gibi, bu yöntem kullanımdan kaldırılmıştır. Daha yeni bir çözüm için @ trolle cevabına bakınız.
Pascal

Bir tıklama işleyici tek seferlik bir işe yaramaz şey değildir. Özellikle soruda gösteriliyorsa hacimli ise. Eklediğiniz ve sayfa yaşadığı sürece işini yapmasına izin vermeniz gerekiyor.
Marco Faustinelli

379

.unbind()kullanımdan kaldırılmıştır ve .off()bunun yerine yöntemi kullanmalısınız. Aramadan .off()hemen önce arayın .on().

Bu, tüm olay işleyicilerini kaldıracaktır:

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

Yalnızca kayıtlı 'tıklama' etkinlik işleyicilerini kaldırmak için:

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


Tıkır tıkır çalışıyor! İşlevim .on () bu sorunu çözmeden önce bir kez tıkladıktan sonra iki kez, dört kez ... .off () çalışacaktı.
jumpOnCommand

146

.bir()

Daha iyi bir seçenek .one():

İşleyici, olay türü başına öğe başına en fazla bir kez yürütülür.

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

Birden fazla sınıf olması ve her sınıfın bir kez tıklanması gerekiyorsa,

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

8
En iyi yanıt, bir aptal hack beni kurtardı, bu çok daha iyi o çünkü birden fazla varsa onclickaynı elemana ama farklı yerlerde olayları bu geri kalanını etkilemez iken unbind()ve off()sadece diğer yok edecek onclickler tekrar teşekkür ederim
Fanckush

3
tüm cevapları denedikten sonra, bu benim için tek iş.
neversion

10
Dikkat edilmesi gereken bir nokta, eğer fonksiyonun TIKLA BAŞLA sadece bir kez ateş etmesini istiyorsanız, ancak sonraki tıklamalarda ateş etmeye devam ediyorsanız, bu kelimenin tam anlamıyla sayfanın ömrü boyunca sadece bir kez ateşleyecektir. Bu nedenle mtl'nin off (). On () yöntemiyle yanıtının kullanılması gerekecektir.
Derek Hewitt

1
munchschair, bunun birden fazla nedeni olabilir. İçinde aynı sınıfta birden çok eleman. Veya bir tıklama işleyicisi bir yinelemede birden çok kez kaydedilir.
Shaunak D

3
Benim için çalışmıyor - yine de çoklu tıklama tetiklemeleri - kimliğe sahip yalnızca 1 düğme öğesi olduğu ve yalnızca 1 etkinliğin yakalandığı (tıklama etkinliği) bir anlam ifade etmiyor. Bunun bir jQuery hatası olduğunu düşündüm, ancak muhtemelen bir Bootstrap modal iletişim kutusu hatası.
MC9000

78

Siz) (yani .off bulmak .unbind () veya .stopPropagation () hala belirli bir sorunu çözmezse, kullanmayı deneyin .stopImmediatePropagation () Eğer sadece olay herhangi köpüren olmadan ve yapmadan ele alınması istediğinizde durumlarda büyük İşleri zaten ele alınan diğer olayları etkiler. Gibi bir şey:

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

hile yapar!


Bu, olayı iki kez ateş etmekten alıkoymamın yanı sıra bana da yardımcı oldu, ancak aynı zamanda beni büyük zaman karıştırdı. Bir jQuery UI İletişim Kutusu alanına bağlı bir olay işleyicisinde event.stopImmediatePropagation () yöntemini kullanırsanız, iletişim kutusunun bir nedenden dolayı artık global değişkenlerin en yeni örneğine başvuramayacağı ve bunun yerine global değişkenlerin sürümünü kullanacağı ortaya çıkıyor jQuery UI İletişim Kutusu oluşturma işleminden önce. Yani, örneğin, global değişkeniniz bildirilmiş, ancak jQuery UI İletişim Kutusu oluşturma sırasında başlatılmamışsa, başlatılmamış jQuery UI İletişim Kutusu olay işleyicisi
UkraineTrain

1
veya jQuery UI Dialog'unu oluşturmadan önce bir küresel değişkene daha sonra 55 olarak değiştirilen bir 16 değeri atadıysanız, o zaman bile, 16 o jQuery UI Dialog olay işleyicisinde bu global değişken için görünecektir. 16. Artık, insanların farkında olması gereken bir jQuery kullanıcı arayüzü hatası gibi görünüyor.
UkraynaTrain

Tarif edilmesi bile zor olan çok spesifik durumlar için. Tam olarak söylediğin gibi çalışır: "Başka hiçbir olayı etkilemeden çalışır". Teşekkür ederim! :)
Toms Bugna

Benim için tamamen iyi çalışıyor. Teşekkürler!
Somnath Pawar

18

Bu işlevi her "tıklama" ya çağırıyorsanız , her çağrıya başka bir çift işleyici ekler .

JQuery ile işleyiciler eklemek "onclick" özelliğinin değerini ayarlamak gibi değildir. Bir kişi, istediği kadar işleyici ekleyebilir.


4
Cevabınız beni doğru yöne getirdi ve çok şey öğrendim, ancak maalesef jQuery kullanarak sorunumu çözmek için yeterli değil. :) Açma / kapama, canlı (ve delege) / die ve birini kullanarak denedim ve sonra addEventListener / removeEventListener, ama yapabileceğim en iyi işleyicilerin üstel büyümesini yavaşlattı. Sonunda şu an için onclick ile olan sorunumu çözdüm. Ama hala cevabınızdan Javascript'in yakalama / köpürme gibi olay modeli hakkında çok şey öğrendim, bu yüzden takdir ediyorum. Teşekkür ederim. :)
Gregory Fowler

Çok teşekkür ederim, bunu bilmediğime inanamıyorum!
Lenny

12

bir Etkinlik birden çok kez kaydedildiğinde (aynı işleyiciye bile olsa) birden çok kez tetiklenir.

örneğin $("ctrl").on('click', somefunction), bu kod parçası sayfanın bir kısmı her yenilendiğinde yürütülürse, etkinlik her seferinde de kaydedilmektedir. Bu nedenle, ctrl yalnızca "bir işlev" i birden çok kez çalıştırabildiğinde bile, kaç kez yürütüldüğüne, kaç kez kaydedildiğine bağlı olacaktır.

bu, javascript'te kayıtlı herhangi bir olay için geçerlidir.

çözüm:

"açık" ı yalnızca bir kez aramayı unutmayın.

ve bir nedenle mimariyi kontrol edemiyorsanız bunu yapın:

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


Gerçekten ne söylemek istiyorsun?
Somnath Kharat

Bu, bu durumda neler olduğunu açıklamaz. Düğmenin benzersiz bir kimliği ve yalnızca 1 etkinliği vardır (yalnızca bir kez tıklanabileceğinden birden çok kez çağrılmaz). Bu sadece jQuery iletişim kutularında (ve çoğaltılması çok kolay) görünen bir hatadır.
MC9000

2
"pushBetButtons" işlevinin yalnızca bir kez mi yoksa birden çok kez mi çağrıldığını bilmiyoruz .. Bir defadan fazla çağrılırsa, olay birden çok kez kaydedildiğinden ve dolayısıyla birden fazla kez tetiklenirse ... .
Kalpesh Popat

4

İşaretleme nedeniyle bir sorunum vardı.

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

Ben html iki kez aynı sınıf 'myclass' var fark, bu yüzden div her örneği için tıklayın çağırır.


3

Daha iyi bir seçenek kullanarak olacağını kapalı

<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 () ve .one () ile ilgili her şey harika ve jquery harika.

Ancak bazen, kullanıcının tıklamasına izin verilmediğinden biraz daha açık olmasını istersiniz ve bu gibi durumlarda böyle bir şey yapabilirsiniz:

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

ve düğmeniz şöyle görünecektir:

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

1
Bu, aslında birden çok kez tıklayan bir kullanıcının durumunu çözecektir, ancak ... Aynı zaman damgasıyla birden fazla tıklama etkinliği alıyorum. Aynı milisaniyede 3 kez tıklamamın bir yolu yok, çok hızlı olsam bile (ve bir kaç kez düğmeye bastığımı bilmiyordum).
jpaugh

2

Belirli bir olayın aynı öğeye birden çok kez bağlanması nedeniyle olur.

Benim için çalışan çözüm:

.die()Yöntemle eklenen tüm olayları öldür .

Ardından yöntem dinleyicinizi ekleyin.

Böylece,

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

olmalı:

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

2

Biz gerekir stopPropagation()Tıklamalar tetikler olay çok kez önlemek siparişi.

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

Olayın DOM ağacını kabarmasını önler, böylece üst işleyicilerin olay hakkında bilgilendirilmesini önler. Bu yöntem hiçbir argümanı kabul etmez.

event.isPropagationStopped()Bu yöntemin çağrılıp çağrılmadığını belirlemek için kullanabiliriz (bu olay nesnesinde).

Bu yöntem, trigger () ile tetiklenen özel etkinlikler için de çalışır. Bunun, aynı öğedeki diğer işleyicilerin çalışmasını engellemeyeceğini unutmayın.


2

Benim durumumda 'delege' kullanıyordum, bu yüzden bu çözümlerin hiçbiri işe yaramadı. Çoklu tıklama sorununa neden olan ajax çağrıları ile birden çok kez görünen düğme olduğuna inanıyorum. Çözümler bir zaman aşımı kullanıyordu, bu nedenle yalnızca son tıklama tanındı:

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
$(element).click(function (e)
{
  if(e.timeStamp !== 0) // This will prevent event triggering more then once
   {
      //do your stuff
   }
}

1

.one, sayfanın ömrü boyunca yalnızca bir kez tetiklenir

Doğrulama yapmak istiyorsanız, bu doğru çözüm değildir, çünkü doğrulamadan sonra sayfadan ayrılmazsanız, asla geri gelmezsiniz. Kullanımı daha iyi

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

Bu konuyu ele aldığımda her zaman şunu kullanıyorum:

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

Bu şekilde aynı strokta bağlarım ve yeniden bağlarım.


0

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

Etkinliğin her zaman yalnızca bir kez tetiklendiğinden emin olmak için Jquery .one () kullanabilirsiniz. JQuery bir olay işleyicisi yalnızca bir kez çağırılmasını sağlar. Ayrıca, geçerli tıklama işleminin işlenmesini tamamladığınızda daha fazla tıklamaya izin vermek için olay işleyicinize bir abone olabilirsiniz.

<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

Şu şekilde deneyin:

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

0

Benim durumumda, onclick olayı defalarca ateş ediyordu çünkü karşılaştırmalı olarak genel bir olay işleyicisi yapmıştım

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

olarak değiştirildi

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

ayrıca statik sekme tıklaması için statik ve dinamik tıklamalar için ayrı işleyiciler yapmalısınız

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

0

Benim durumumda *.js, sayfaya aynı dosyayı bir <script>etikete iki kez yükledim, bu nedenle her iki dosya da öğeye olay işleyicileri ekliyordu. Yinelenen bildirimi kaldırdım ve bu sorun çözüldü.


0

Birden fazla sınıfınız varsa ve etikete tıklarken radyo düğmeleriyle uğraşıyorsanız bulduğum başka bir çözüm de buydu.

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

Dinamik olarak oluşturulan bir bağlantı ile bu sorunu yaşıyordu:

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

Ben yerine bulundu documentile 'body'benim için sabit konuya:

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


0

Unbind () çalışır, ancak bu gelecekte başka sorunlara neden olabilir. İşleyici, başka bir işleyicinin içindeyken birden çok kez tetiklenir, bu nedenle işleyicinizi dışarıda tutun ve iç içe geçmiş işleyicinin değerlerini istiyorsanız, bunları işleyicinizin erişebileceği genel bir değişkene atayın.



-1

Aşağıdaki kod, birden çok fare tıklaması tetikleme olayını bir kereden fazla işlemek için sohbet uygulamamda çalıştı. if (!e.originalEvent.detail || e.originalEvent.detail == 1) { // Your code logic }

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.