acara klik jQuery menembak beberapa kali

284

Saya mencoba untuk menulis permainan video poker dalam Javascript sebagai cara untuk mendapatkan dasar-dasar itu, dan saya telah mengalami masalah di mana penangan event klik jQuery menembak beberapa kali.

Mereka melekat pada tombol untuk menempatkan taruhan, dan itu berfungsi dengan baik untuk menempatkan taruhan di tangan pertama selama pertandingan (menembak hanya sekali); tetapi dalam bertaruh untuk tangan kedua, ia menyalakan acara klik dua kali setiap kali taruhan atau tombol taruhan tempat ditekan (jadi dua kali jumlah yang benar adalah taruhan untuk setiap pers). Secara keseluruhan, ini mengikuti pola ini untuk berapa kali acara klik dilepaskan saat menekan tombol taruhan sekali - di mana istilah h urutannya adalah untuk taruhan tangan ke - h dari awal permainan: 1, 2, 4 , 7, 11, 16, 22, 29, 37, 46, yang tampaknya n (n + 1) / 2 +1 untuk apa pun yang bernilai - dan saya tidak cukup pintar untuk mengetahuinya, saya menggunakan OEIS . :)

Inilah fungsi dengan pengendali acara klik yang beraksi; semoga mudah dimengerti (beri tahu saya jika tidak, saya juga ingin menjadi lebih baik):

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

Tolong beri tahu saya jika Anda memiliki ide atau saran, atau jika solusi untuk masalah saya mirip dengan solusi untuk masalah lain di sini (Saya telah melihat banyak utas yang berjudul sama dan tidak beruntung dalam menemukan solusi yang dapat bekerja untuk saya).

Gregory Fowler
sumber
var amount = parseInt(this.id.replace(/[^\d]/g,''),10);Dan jika Anda akan menggunakan properti yang sama dari suatu elemen lebih dari satu kali cache properti itu, jangan terus mencarinya. Pencarian itu mahal.
David mengatakan mengembalikan Monica
Terima kasih atas tanggapannya, dan tip tentang properti caching. Saya mengatur player.money dan player.bet ke variabel lokal uang dan bertaruh di dalam fungsi itu dan memanipulasinya, dan akan mengubah sisa kode saya untuk melakukan itu juga. :) Jika Anda punya waktu, bisakah Anda juga menjelaskan apa yang Anda sarankan inisialisasi jumlah sedang dilakukan; sepertinya ekspresi reguler, tapi aku tidak bisa memahaminya dengan mudah.
Gregory Fowler
@GregoryFowler - tidak terkait dengan pertanyaan Anda, tapi ... pernyataan pergantian javascript mungkin layak dilihat.
Clayton
2
Man, fungsi Anda adalah menempatkan pengendali klik setiap kali dipanggil. Jika Anda memanggilnya di setiap ronde, di ronde kedua Anda memiliki dua penangan dan sebagainya. Setiap pawang melakukan tugasnya dan pada putaran 100 Anda mendapatkan 100 peringatan.
Marco Faustinelli
Ini terjadi karena di suatu tempat di dalam kode Anda, Anda membatalkan event handler tanpa terlebih dahulu melepasnya. Lihat pertanyaan ini untuk skenario serupa , dan penjelasan yang bagus.
jpaugh

Jawaban:

528

Untuk memastikan tindakan klik saja sekali gunakan ini:

$(".bet").unbind().click(function() {
    //Stuff
});
rampok
sumber
31
OK, di mana Anda kemarin, Rob? ;) Itulah tepatnya yang saya cari, tidak tahu mengapa saya tidak menemukannya sebelumnya. Tetapi itu masih merupakan berkah tersembunyi karena saya memang belajar banyak hal lain.
Gregory Fowler
1
;) maaf. Saya memutar roda saya selama beberapa hari untuk yang ini juga. Saya masih mencari alasan logis mengapa hal itu terjadi.
Rob
6
Man setelah banyak hal ini berhasil. Kecuali dalam kasus saya, saya menggunakan yang setara dengan: $ (". Taruhan"). Off (). On ()
MadTurki
7
Seperti yang dikatakan jroi_web di bawah ini, metode ini sudah usang. Lihat jawaban @ trolle untuk solusi yang lebih baru.
Pascal
Pawang klik bukan hal yang mudah dibuang. Terutama ketika itu besar jika-jika-jika ditunjukkan dalam pertanyaan. Anda seharusnya melampirkannya dan membiarkannya berfungsi selama laman itu hidup.
Marco Faustinelli
380

.unbind()sudah usang dan Anda harus menggunakan .off()metode ini sebagai gantinya. Cukup panggil .off()tepat sebelum Anda menelepon .on().

Ini akan menghapus semua penangan acara:

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

Untuk hanya menghapus penangan acara 'klik' yang terdaftar:

$(element).off('click').on('click', function() {
    // function body
});
mtl
sumber
9
ini harus digunakan dalam versi jQuery yang lebih baru karena unbind, die, atau live sudah usang
jroi_web
Bekerja seperti pesona! Fungsi saya akan berjalan sekali saat klik, kemudian dua kali, empat kali ... .off () sebelum .on () menyelesaikan masalah ini.
jumpOnCommand
146

.satu()

Pilihan yang lebih baik adalah .one():

Pawang dieksekusi paling banyak sekali per elemen per jenis peristiwa.

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

Dalam hal beberapa kelas dan setiap kelas perlu diklik sekali,

$(".bet").on('click',function() {
    //Your function
    $(this).off('click');   //or $(this).unbind()
});
Shaunak D
sumber
8
jawaban terbaik, Anda menyelamatkan saya dari hack konyol, ini jauh lebih baik karena jika Anda memiliki beberapa onclickacara ke elemen yang sama tetapi di lokasi yang berbeda ini tidak akan mempengaruhi sisanya, sementara unbind()dan off()hanya akan menghancurkan yang lain onclickterima kasih lagi
Fanckush
3
setelah mencoba semua jawaban, yang ini adalah satu-satunya yang bekerja untuk saya.
neversion
10
Satu hal yang perlu diperhatikan, jika Anda ingin fungsi hanya menyala sekali PER KLIK, tetapi terus jalankan pada klik berikutnya, yang satu ini benar-benar hanya akan memecat sekali untuk seumur hidup halaman. Jadi jawaban mtl dengan metode off (). On () perlu digunakan.
Derek Hewitt
1
@munchschair, mungkin ada beberapa alasan untuk ini. Beberapa elemen dengan kelas yang sama di dalam satu sama lain. Atau penangan klik terdaftar beberapa kali dalam iterasi.
Shaunak D
3
Tidak berfungsi untuk saya - masih beberapa klik firef - tidak masuk akal karena hanya ada 1 elemen tombol dengan ID dan hanya 1 peristiwa yang terperangkap (peristiwa klik). Saya pikir ini adalah bug jQuery, tapi itu mungkin bug modal-dialog Bootstrap.
MC9000
78

Jika Anda menemukan .off () .unbind () atau .stopPropagation () masih tidak memperbaiki masalah spesifik Anda, coba gunakan .stopImmediatePropagation () Berfungsi bagus dalam situasi ketika Anda hanya ingin acara Anda ditangani tanpa gelembung dan tanpa gelembung mempengaruhi semua acara lain yang sudah ditangani. Sesuatu seperti:

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

lakukan triknya!

Alfonse Pinto
sumber
Ini membantu saya dan bahkan menghentikan acara dari menembak dua kali, tetapi juga mengacaukan waktu saya. Ternyata jika Anda menggunakan event.stopImmediatePropagation () dalam pengendali event yang dilampirkan ke bidang Dialog jQuery UI, maka, untuk beberapa alasan, dialog tidak lagi dapat merujuk contoh variabel global terbaru dan sebagai gantinya menggunakan versi variabel global sebelum rendering Dialog UI jQuery. Berarti, bahwa jika, misalnya, variabel global Anda dideklarasikan, tetapi tidak diinisialisasi pada saat rendering Dialog jQuery UI, maka itu akan ditampilkan sebagai handler event handler jQuery UI Dialog yang tidak diinisialisasi
UkraineTrain
1
atau jika Anda ditugaskan ke beberapa variabel global nilai 16 sebelum rendering Dialog UI jQuery, yang kemudian berubah menjadi, katakanlah, 55, maka 16 akan muncul untuk variabel global di event handler jQuery UI Dialog, bahkan jika pada saat itu tidak lagi 16. Jadi, sepertinya bug jQuery UI yang harus diperhatikan orang.
UkraineTrain
Untuk situasi yang sangat spesifik yang bahkan sulit digambarkan. Ini bekerja persis seperti yang Anda katakan: "Bekerja tanpa memengaruhi acara lainnya". Terima kasih! :)
Toms Bugna
Bekerja dengan sangat baik untuk saya. Terima kasih!
Somnath Pawar
18

Jika Anda memanggil fungsi itu di setiap "klik", maka itu menambahkan sepasang penangan pada setiap panggilan.

Menambahkan penangan dengan jQuery tidak seperti mengatur nilai atribut "onclick". Satu dapat menambahkan penangan sebanyak yang diinginkan.

Runcing
sumber
4
Jawaban Anda membuat saya ke arah yang benar dan saya belajar banyak, tetapi sayangnya tidak cukup untuk menyelesaikan masalah saya menggunakan jQuery. :) Saya mencoba menggunakan on / off, hidup (dan mendelegasikan) / mati, dan satu, dan kemudian addEventListener / removeEventListener, tetapi yang terbaik yang bisa saya lakukan adalah memperlambat pertumbuhan eksponensial penangan. Saya akhirnya hanya memecahkan masalah saya dengan onclick untuk saat ini. Tapi saya masih belajar banyak tentang model acara Javascript, seperti menangkap / menggelegak, dari jawaban Anda, jadi saya menghargainya. Terima kasih. :)
Gregory Fowler
Terima kasih banyak, saya tidak percaya saya tidak tahu ini!
Lenny
12

suatu Acara akan memecat beberapa kali ketika terdaftar beberapa kali (bahkan jika ke penangan yang sama).

misalnya $("ctrl").on('click', somefunction) jika potongan kode ini dieksekusi setiap kali halaman di-refresh sebagian, peristiwa itu juga terdaftar setiap kali. Oleh karena itu bahkan jika ctrl diklik hanya sekali ia dapat menjalankan "fungsi" beberapa kali - berapa kali dieksekusi akan tergantung pada berapa kali terdaftar.

ini berlaku untuk semua acara yang terdaftar dalam javascript.

larutan:

pastikan untuk memanggil "aktif" hanya sekali.

dan untuk beberapa alasan jika Anda tidak dapat mengontrol arsitektur maka lakukan ini:

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

Kalpesh Popat
sumber
Apa yang ingin Anda katakan?
Somnath Kharat
Itu tidak menjelaskan apa yang terjadi dalam kasus ini. Tombol ini memiliki satu ID unik dan hanya 1 acara (BUKAN disebut berkali-kali, karena hanya dapat diklik sekali). Ini adalah bug yang hanya muncul di kotak dialog jQuery (dan sangat mudah direproduksi).
MC9000
2
kita tidak tahu apakah fungsi "pushingBetButtons" dipanggil hanya sekali atau beberapa kali .. jika dipanggil lebih dari sekali, maka acara tersebut terdaftar beberapa kali dan karenanya juga akan mem-multipletime .. bahkan jika tombol diklik sekali saja .
Kalpesh Popat
4

Saya punya masalah karena markup.

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

Anda perhatikan saya memiliki kelas yang sama 'myclass' dua kali dalam html, sehingga ia memanggil klik untuk setiap instance div.

Bobz
sumber
3

Opsi yang lebih baik adalah menggunakan 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>
arc_shiva
sumber
3

Semua hal tentang .on () dan .one () bagus, dan jquery hebat.

Tetapi kadang-kadang, Anda ingin menjadi sedikit lebih jelas bahwa pengguna tidak boleh mengklik, dan dalam hal ini Anda bisa melakukan sesuatu seperti ini:

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

dan tombol Anda akan terlihat seperti:

<button onclick='funName()'>Click here</button>
rikkitikkitumbo
sumber
1
Itu akan menyelesaikan kasus pengguna yang benar-benar mengklik beberapa kali, tapi ... Saya mendapatkan beberapa acara klik dengan stempel waktu yang sama. Tidak mungkin saya bisa mengklik 3 kali dalam milidetik yang sama, bahkan jika saya sangat cepat dalam hal itu (dan entah bagaimana tidak menyadari berapa kali saya menekan tombol).
jpaugh
2

Itu terjadi karena peristiwa tertentu terikat beberapa kali ke elemen yang sama.

Solusi yang berhasil bagi saya adalah:

Bunuh semua acara yang dilampirkan menggunakan .die() metode.

Dan kemudian lampirkan pendengar metode Anda.

Jadi,

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

seharusnya:

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

Kita harus untuk. stopPropagation()Untuk menghindari klik memicu peristiwa terlalu banyak.

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

Ini Mencegah acara dari menggelegak pohon DOM, mencegah penangan orang tua diberitahu tentang acara tersebut. Metode ini tidak menerima argumen apa pun.

Kita dapat menggunakan event.isPropagationStopped()untuk menentukan apakah metode ini pernah dipanggil (pada objek peristiwa itu).

Metode ini juga berfungsi untuk acara khusus yang dipicu dengan trigger (). Perhatikan bahwa ini tidak akan mencegah penangan lain pada elemen yang sama berjalan.

Daniel Raja Singh
sumber
2

Dalam kasus saya, saya menggunakan 'delegate', jadi tidak ada solusi yang berhasil. Saya percaya itu adalah tombol yang muncul beberapa kali melalui panggilan ajax yang menyebabkan masalah banyak klik. Solusinya menggunakan batas waktu sehingga hanya klik terakhir yang dikenali:

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

.satu-satunya kebakaran satu kali selama masa pakai halaman

Jadi jika Anda ingin melakukan validasi, ini bukan solusi yang tepat, karena ketika Anda tidak meninggalkan halaman setelah validasi, Anda tidak akan pernah kembali. Lebih baik digunakan

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

Ketika saya menangani masalah ini, saya selalu menggunakan:

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

Dengan cara ini saya melepaskan ikatan dan rebind pada stroke yang sama.

Andy
sumber
0

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

Untuk memastikan bahwa peristiwa selalu hanya terjadi satu kali, Anda dapat menggunakan Jquery .one (). JQuery one memastikan bahwa event handler Anda hanya menelepon sekali. Selain itu, Anda dapat berlangganan pengendali acara Anda dengan satu untuk memungkinkan klik lebih lanjut ketika Anda telah selesai memproses operasi klik saat ini.

<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();
Razan Paul
sumber
0

Coba seperti itu:

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

Dalam kasus saya, event onclick diaktifkan beberapa kali karena saya membuat event handler generik sebagai perbandingan

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

diubah menjadi

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

dan juga harus membuat penangan terpisah untuk klik statis dan dinamis, untuk klik tab statis

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

Dalam kasus saya, saya telah memuat *.jsfile yang sama pada halaman dua kali dalam sebuah <script>tag, sehingga kedua file melampirkan pengendali acara ke elemen. Saya menghapus deklarasi duplikat dan itu memperbaiki masalah.

inostia
sumber
0

Solusi lain yang saya temukan adalah ini, jika Anda memiliki beberapa kelas dan berurusan dengan tombol radio sambil mengklik label.

$('.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();
    }
});
Andrew Vink
sumber
0

Saya mengalami masalah ini dengan tautan yang dibuat secara dinamis:

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

Saya menemukan mengganti documentdengan 'body'memperbaiki masalah untuk saya:

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

nateM
sumber
0

Unbind () berfungsi, tetapi itu dapat menyebabkan masalah lain di masa depan. Pawang memicu beberapa kali ketika berada di dalam pawang lain, jadi simpan pawang Anda di luar dan jika Anda ingin nilai-nilai pawang yang bersarang, tetapkan mereka ke variabel global sehingga dapat diakses oleh pawang Anda.

Praveen Poonja
sumber
0

Dalam hal ini berfungsi dengan baik

$( "#ok" ).bind( "click", function() {
    console.log("click"); 
});
santosh vishwakarma
sumber
-1

Kode di bawah ini berfungsi untuk saya dalam aplikasi obrolan saya untuk menangani beberapa peristiwa pemicu klik mouse lebih dari satu kali. if (!e.originalEvent.detail || e.originalEvent.detail == 1) { // Your code logic }

pengguna2792303
sumber