Các sự kiện nhấp chuột jQuery bắn nhiều lần


283

Tôi đang cố gắng viết một trò chơi video poker bằng Javascript như một cách để giảm bớt những điều cơ bản của nó và tôi đã gặp phải một vấn đề trong đó các trình xử lý sự kiện nhấp chuột jQuery đang bắn nhiều lần.

Chúng được gắn vào các nút để đặt cược và nó hoạt động tốt khi đặt cược vào tay đầu tiên trong trò chơi (chỉ bắn một lần); nhưng khi đặt cược cho ván bài cũ, nó sẽ kích hoạt sự kiện nhấp hai lần mỗi lần nhấn nút đặt cược hoặc đặt cược (do đó, gấp đôi số tiền chính xác được đặt cho mỗi lần nhấn). Nhìn chung, nó tuân theo mô hình này cho số lần sự kiện nhấp được kích hoạt khi nhấn nút đặt cược một lần - trong đó thuật ngữ thứ i của chuỗi là để đặt cược cho ván bài thứ i từ đầu trò chơi: 1, 2, 4 , 7, 11, 16, 22, 29, 37, 46, dường như là n (n + 1) / 2 + 1 cho bất cứ điều gì đáng giá - và tôi không đủ thông minh để hiểu rằng, tôi đã sử dụng OEIS . :)

Đây là chức năng với các trình xử lý sự kiện nhấp đang hoạt động; hy vọng nó dễ hiểu (cho tôi biết nếu không, tôi cũng muốn cải thiện điều đó):

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

Vui lòng cho tôi biết nếu bạn có bất kỳ ý tưởng hoặc đề xuất nào hoặc nếu giải pháp cho vấn đề của tôi tương tự như giải pháp cho một vấn đề khác ở đây (Tôi đã xem xét nhiều chủ đề có tiêu đề tương tự và không gặp may mắn trong việc tìm giải pháp có thể hoạt động cho tôi).


var amount = parseInt(this.id.replace(/[^\d]/g,''),10);Và nếu bạn sẽ sử dụng cùng một thuộc tính của một phần tử nhiều lần bộ đệm thuộc tính đó, đừng tiếp tục tìm kiếm nó. Việc tìm kiếm là đắt tiền.
David nói phục hồi Monica

Cảm ơn bạn đã phản hồi và lời khuyên về các thuộc tính bộ đệm. Tôi đặt player.money và player.bet thành tiền biến cục bộ và đặt cược vào chức năng đó và thay vào đó thao túng chúng và sẽ thay đổi phần còn lại của mã của tôi để làm điều đó. :) Nếu bạn có thời gian, bạn cũng có thể giải thích những gì bạn đề xuất khởi tạo số tiền đang làm; nó trông giống như một số biểu hiện thông thường, nhưng tôi không thể hiểu ý nghĩa của nó một cách dễ dàng.
Gregory Fowler

@GregoryFowler - không liên quan đến câu hỏi của bạn, nhưng ... một câu lệnh chuyển đổi javascript có thể đáng để xem xét.
Clayton

2
Man, chức năng của bạn đang đặt một trình xử lý nhấp chuột mỗi khi nó được gọi. Nếu bạn gọi nó ở mỗi vòng, ở vòng hai bạn có hai người xử lý và cứ thế. Mỗi người xử lý thực hiện công việc của mình và tại vòng 100, bạn nhận được 100 thông báo.
Marco Faustinelli

Điều này xảy ra bởi vì ở đâu đó trong mã của bạn, bạn đang chỉnh lại trình xử lý sự kiện mà không cần mở khóa đầu tiên. Xem câu hỏi này cho một kịch bản tương tự , và một lời giải thích tốt.
jpaugh

Câu trả lời:


526

Để đảm bảo một lần nhấp chỉ hành động một lần sử dụng này:

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

31
OK, hôm qua bạn ở đâu, Rob? ;) Đó chính xác là những gì tôi đang tìm kiếm, không biết tại sao tôi không tìm thấy nó trước đây. Nhưng đó vẫn là một phước lành trong việc ngụy trang vì tôi đã học được rất nhiều thứ khác.
Gregory Fowler

1
;) lấy làm tiếc. Tôi quay bánh xe của tôi xung quanh một vài ngày trên cái này quá. Tôi vẫn đang tìm kiếm một lý do hợp lý là tại sao nó thậm chí xảy ra ở nơi đầu tiên.
Cướp

6
Người đàn ông sau rất nhiều điều này đã làm điều đó. Ngoại trừ trong trường hợp của tôi, tôi đã sử dụng tương đương: $ (".
Cược

7
Như jroi_web nói dưới đây, phương pháp này không được chấp nhận. Xem câu trả lời của @ trolle cho một giải pháp gần đây hơn.
Pascal

Một trình xử lý nhấp chuột không phải là một thứ bỏ đi một lần. Đặc biệt là khi nó cồng kềnh nếu-nếu-nếu hiển thị trong câu hỏi. Bạn phải gắn nó và để nó hoạt động miễn là trang còn tồn tại.
Marco Faustinelli

378

.unbind()không được dùng nữa và bạn nên sử dụng .off()phương pháp thay thế. Đơn giản chỉ cần gọi .off()ngay trước khi bạn gọi .on().

Điều này sẽ loại bỏ tất cả các trình xử lý sự kiện:

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

Để chỉ xóa trình xử lý sự kiện 'nhấp' đã đăng ký:

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

9
điều này nên được sử dụng trong phiên bản mới hơn của jQuery vì không liên kết, chết hoặc sống đã bị phản đối
jroi_web

Hoạt động như một lá bùa! Hàm của tôi sẽ chạy một lần khi nhấp, sau đó hai lần, bốn lần ... .off () trước .on () đã giải quyết vấn đề này.
jumpOnCommand

146

.một()

Một lựa chọn tốt hơn sẽ là .one():

Trình xử lý được thực thi nhiều nhất một lần cho mỗi phần tử cho mỗi loại sự kiện.

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

Trong trường hợp có nhiều lớp và mỗi lớp cần được bấm một lần,

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

8
Câu trả lời hay nhất, bạn đã cứu tôi khỏi một vụ hack ngớ ngẩn, điều này tốt hơn nhiều vì nếu bạn có nhiều onclicksự kiện cho cùng một yếu tố nhưng ở các địa điểm khác nhau, điều này sẽ không ảnh hưởng đến phần còn lại, trong khi unbind()off()sẽ phá hủy onclickcảm ơn của bạn một lần nữa
Fanckush

3
Sau khi thử tất cả các câu trả lời, đây là công việc duy nhất cho tôi.
neversion

10
Một điều cần lưu ý, nếu bạn muốn chức năng chỉ kích hoạt một lần PER PER, nhưng tiếp tục kích hoạt các lần nhấp tiếp theo, thì điều này theo nghĩa đen sẽ chỉ kích hoạt một lần cho vòng đời của trang. Vì vậy, câu trả lời của mtl với phương thức off (). On () sẽ cần được sử dụng.
Derek Hewitt

1
@munchschair, có thể có nhiều lý do cho việc này. Nhiều yếu tố với cùng một lớp bên trong nhau. Hoặc một trình xử lý nhấp chuột được đăng ký nhiều lần trong một lần lặp.
Shaunak D

3
Không hoạt động đối với tôi - vẫn có nhiều lần nhấp chuột - không có ý nghĩa gì vì chỉ có 1 yếu tố nút với ID và chỉ có 1 sự kiện bị mắc kẹt (sự kiện nhấp chuột). Tôi nghĩ rằng đây là một lỗi jQuery, nhưng nó có thể là một lỗi hộp thoại phương thức Bootstrap.
MC9000

78

Nếu bạn thấy rằng .off () .unbind () hoặc .stopPropagation () vẫn không khắc phục được sự cố cụ thể của bạn, hãy thử sử dụng .stopImmediatePropagation () Hoạt động tuyệt vời trong các tình huống khi bạn chỉ muốn xử lý sự kiện của mình mà không có bất kỳ sự cố nào. ảnh hưởng đến bất kỳ sự kiện nào khác đã được xử lý. Cái gì đó như:

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

lừa


Điều này đã giúp tôi cũng như ngăn chặn sự kiện bắn hai lần, nhưng cũng làm tôi bực mình. Nó chỉ ra rằng nếu bạn sử dụng event.stopImmediatePropagation () trong một trình xử lý sự kiện được gắn vào trường Hộp thoại UI UI, thì vì một lý do nào đó, hộp thoại không còn có thể tham chiếu phiên bản mới nhất của biến toàn cục và thay vào đó sử dụng phiên bản của biến toàn cục trước khi kết xuất hộp thoại UI UI. Có nghĩa là, ví dụ, nếu, ví dụ, biến toàn cục của bạn đã được khai báo, nhưng không được khởi tạo tại thời điểm kết xuất Hộp thoại UI UI, thì nó sẽ hiển thị dưới dạng trình xử lý sự kiện UI UI chưa được khởi tạo
UkraineTrain

1
hoặc nếu bạn đã gán cho một số biến toàn cầu một giá trị 16 trước khi hiển thị Hộp thoại UI UI, sau này đổi thành 55, thì 16 sẽ hiển thị cho biến toàn cục đó trong trình xử lý sự kiện Hộp thoại UI UI, ngay cả khi đó không còn 16. Vì vậy, nó trông giống như một lỗi UI UI mà mọi người nên biết.
UkraineTrain

Đối với các tình huống rất cụ thể thậm chí rất khó để mô tả. Nó hoạt động chính xác như Bạn đã nói: "Hoạt động mà không ảnh hưởng đến bất kỳ sự kiện nào khác". Cảm ơn bạn! :)
Toms Bugna

Hoạt động hoàn toàn tốt cho tôi. Cảm ơn!
Somnath Pawar

18

Nếu bạn đang gọi chức năng đó trên mỗi "lần nhấp", thì đó là thêm một cặp trình xử lý khác cho mỗi cuộc gọi.

Thêm trình xử lý với jQuery không giống như đặt giá trị của thuộc tính "onclick". Người ta có thể thêm nhiều người xử lý như một mong muốn.


4
Câu trả lời của bạn đặt tôi đi đúng hướng và tôi đã học được rất nhiều, nhưng không đủ để giải quyết vấn đề của mình khi sử dụng jQuery. :) Tôi đã thử sử dụng bật / tắt, trực tiếp (và ủy nhiệm) / die và một, sau đó addEventListener / removeEventListener, nhưng điều tốt nhất tôi có thể làm là làm chậm sự tăng trưởng theo cấp số nhân của trình xử lý. Cuối cùng tôi cũng chỉ giải quyết được vấn đề của mình với onclick. Nhưng tôi vẫn học được rất nhiều về mô hình sự kiện của Javascript, như chụp / sủi bọt, từ câu trả lời của bạn, vì vậy tôi đánh giá cao nó. Cảm ơn bạn. :)
Gregory Fowler

Cảm ơn bạn rất nhiều, tôi không thể tin rằng tôi đã không biết điều này!
Lenny

12

một sự kiện sẽ kích hoạt nhiều lần khi nó được đăng ký nhiều lần (ngay cả khi cùng một trình xử lý).

ví dụ: $("ctrl").on('click', somefunction)nếu đoạn mã này được thực thi mỗi khi trang được làm mới một phần, thì sự kiện cũng được đăng ký mỗi lần. Do đó, ngay cả khi ctrl chỉ được nhấp một lần, nó có thể thực thi "một số chức năng" nhiều lần - số lần thực thi sẽ phụ thuộc vào số lần đăng ký.

điều này đúng với bất kỳ sự kiện nào được đăng ký trong javascript.

giải pháp:

đảm bảo chỉ gọi "bật" một lần.

và vì một số lý do nếu bạn không thể kiểm soát kiến ​​trúc thì hãy làm điều này:

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


Bạn thực sự muốn nói gì?
Somnath Kharat

Điều đó không giải thích những gì đang xảy ra trong trường hợp này. Nút này có một ID duy nhất và chỉ có 1 sự kiện (nó KHÔNG được gọi nhiều lần, vì nó chỉ có thể được bấm một lần). Đây là một lỗi chỉ xuất hiện trong hộp thoại jQuery (và rất dễ tái tạo).
MC9000

2
chúng tôi không biết chức năng "pushBetButtons" chỉ được gọi một lần hay nhiều lần .. nếu nó được gọi nhiều lần, hơn là sự kiện được đăng ký nhiều lần và do đó, nó cũng sẽ kích hoạt nhiều lần..tất cả nếu nút chỉ được nhấp một lần .
Kalpesh Popat

4

Tôi đã có một vấn đề vì đánh dấu.

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

Bạn nhận thấy tôi có cùng một lớp 'mygroup' hai lần trong html, vì vậy nó gọi nhấp cho mỗi phiên bản của div.


3

Tùy chọn tốt hơn sẽ được sử dụng tắt

<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

Tất cả những thứ về .on () và .one () là tuyệt vời, và jquery là tuyệt vời.

Nhưng đôi khi, bạn muốn rõ ràng hơn một chút rằng người dùng không được phép nhấp và trong những trường hợp đó bạn có thể làm một cái gì đó như thế này:

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

và nút của bạn sẽ trông như sau:

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

1
Điều đó sẽ giải quyết trường hợp người dùng thực sự nhấp nhiều lần, nhưng ... Tôi đang nhận được nhiều sự kiện nhấp chuột với cùng dấu thời gian. Không có cách nào tôi có thể nhấp 3 lần trong cùng một mili giây, ngay cả khi tôi cực kỳ nhanh nhạy với nó (và bằng cách nào đó không biết tôi đã nhấn nút bao nhiêu lần).
jpaugh

2

Nó xảy ra do sự kiện cụ thể bị ràng buộc nhiều lần với cùng một yếu tố.

Giải pháp hiệu quả với tôi là:

Giết tất cả các sự kiện kèm theo bằng .die()phương pháp.

Và sau đó đính kèm phương thức nghe của bạn.

Như vậy

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

nên là:

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

2

Chúng tôi phải stopPropagation()Để tránh sự kiện kích hoạt Nhấp chuột quá nhiều lần.

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

Nó ngăn chặn sự kiện làm nổi lên cây DOM, ngăn không cho bất kỳ trình xử lý cha mẹ nào được thông báo về sự kiện này. Phương pháp này không chấp nhận bất kỳ đối số.

Chúng ta có thể sử dụng event.isPropagationStopped()để xác định xem phương thức này đã từng được gọi chưa (trên đối tượng sự kiện đó).

Phương thức này cũng hoạt động cho các sự kiện tùy chỉnh được kích hoạt bằng trigger (). Lưu ý rằng điều này sẽ không ngăn các trình xử lý khác trên cùng một phần tử chạy.


2

Trong trường hợp của tôi, tôi đã sử dụng 'đại biểu', vì vậy không có giải pháp nào trong số này hoạt động. Tôi tin rằng đó là nút xuất hiện nhiều lần thông qua các cuộc gọi ajax đã gây ra sự cố nhiều lần nhấp. Các giải pháp đã sử dụng thời gian chờ để chỉ nhận ra lần nhấp cuối cùng:

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 chỉ bắn một lần trong suốt cuộc đời của trang

Vì vậy, trong trường hợp bạn muốn thực hiện xác nhận, đây không phải là giải pháp phù hợp, bởi vì khi bạn không rời khỏi trang sau khi xác thực, bạn sẽ không bao giờ quay lại. Sử dụng tốt hơn

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

Khi tôi giải quyết vấn đề này, tôi luôn sử dụng:

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

Bằng cách này, tôi hủy liên kết và rebind trong cùng một đột quỵ.


0

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

Để đảm bảo sự kiện luôn chỉ diễn ra một lần, bạn có thể sử dụng Jquery .one (). JQuery một đảm bảo rằng trình xử lý sự kiện của bạn chỉ được gọi một lần. Ngoài ra, bạn có thể đăng ký trình xử lý sự kiện của mình với một để cho phép nhấp thêm khi bạn hoàn thành việc xử lý thao tác nhấp hiện tại.

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

Giáo dục

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

Hãy thử theo cách đó:

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

0

Trong trường hợp của tôi, sự kiện onclick đã bắn nhiều lần vì tôi đã thực hiện một trình xử lý sự kiện chung tương đối như

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

thay đổi để

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

và cũng phải tạo các trình xử lý riêng cho các nhấp chuột tĩnh và động, đối với nhấp vào tab tĩnh

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

0

Trong trường hợp của tôi, tôi đã tải cùng một *.jstệp trên trang hai lần trong một <script>thẻ, vì vậy cả hai tệp đều gắn trình xử lý sự kiện vào phần tử. Tôi đã gỡ bỏ khai báo trùng lặp và điều đó đã khắc phục vấn đề.


0

Một giải pháp khác tôi tìm thấy là đây, nếu bạn có nhiều lớp và đang xử lý các nút radio trong khi nhấp vào nhãn.

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

Tôi đã gặp vấn đề này với một liên kết được tạo động:

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

Tôi tìm thấy thay thế documentvới đã 'body'khắc phục vấn đề cho tôi:

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


0

Unbind () hoạt động, nhưng điều đó có thể gây ra các vấn đề khác trong tương lai. Trình xử lý kích hoạt nhiều lần khi nó ở bên trong một trình xử lý khác, vì vậy hãy giữ trình xử lý của bạn ở bên ngoài và nếu bạn muốn các giá trị của trình xử lý được lồng vào nhau, hãy gán chúng cho một biến toàn cục mà trình xử lý của bạn có thể truy cập được.


0

Trong trường hợp này hoạt động tốt

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

-1

Đoạn mã dưới đây hoạt động với tôi trong ứng dụng trò chuyện của tôi để xử lý nhiều lần nhấp chuột kích hoạt các sự kiện nhiều lần. if (!e.originalEvent.detail || e.originalEvent.detail == 1) { // Your code logic }

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.