jQuery: nhiều hơn một trình xử lý cho cùng một sự kiện


137

Điều gì xảy ra nếu tôi liên kết hai trình xử lý sự kiện với cùng một sự kiện cho cùng một phần tử?

Ví dụ:

var elem = $("...")
elem.click(...);
elem.click(...);

Liệu trình xử lý cuối cùng "thắng", hoặc cả hai trình xử lý sẽ được chạy?

Câu trả lời:


168

Cả hai trình xử lý sẽ chạy, mô hình sự kiện jQuery cho phép nhiều trình xử lý trên một phần tử, do đó trình xử lý sau này không ghi đè trình xử lý cũ hơn.

Các trình xử lý sẽ thực hiện theo thứ tự mà chúng bị ràng buộc .


1
Điều gì xảy ra với cách bản địa? và làm thế nào để người bản xứ biết làm thế nào để loại bỏ một cái cụ thể?
SuperUberDuper

1
Theo DOM Cấp 3 (tham chiếu HTML 5 tham chiếu), các trình xử lý sự kiện được thực thi theo thứ tự mà chúng được đăng ký - w3.org/TR/DOM-Level-3-Events/#event-phasew3.org/TR/ 2014 / REC-html5-20141028 / Hoài . Trình xử lý sự kiện có thể được xóa bằng cách chuyển tham chiếu đến trình xử lý đã được đăng ký
Russ Cam

@RussCam điều gì xảy ra nếu một trình xử lý tương tự bị ràng buộc nhiều hơn sau đó một lần cho phép chỉ nói jQuery('.btn').on('click',handlerClick);được gọi ở nhiều nơi mà không thực sự là .offgì?
techie_28

Lưu ý rằng đối với các widget widget của jQueryUI, điều này không đúng nếu bạn đặt trình xử lý làm tùy chọn. Để cả trình xử lý cũ và mới được gọi, bạn cần sử dụng bindphương thức. Xem phần này để biết chi tiết: learn.jquery.com/jquery-ui/widget-factory/,
Michael Scheper

@MichaelScheper vui lòng chỉnh sửa câu trả lời và cập nhật với thông tin bổ sung
Russ Cam

36

Giả sử rằng bạn có hai trình xử lý, fg và muốn đảm bảo rằng chúng được thực thi theo thứ tự đã biết và cố định, sau đó chỉ gói gọn chúng:

$("...").click(function(event){
  f(event);
  g(event);
});

Theo cách này, chỉ có (từ phối cảnh của jQuery) chỉ có một trình xử lý, gọi fg theo thứ tự được chỉ định.


3
+1, đóng gói bên trong một chức năng là cách để đi. Và thậm chí logic có điều kiện tốt hơn có thể được chứa bên trong hàm xử lý để kiểm soát (các) sự kiện được kích hoạt.
Gordon Potter

Một bộ sưu tập các trình xử lý có trình tự được xác định theo chương trình.
Aaron Blenkush

17

.Bind () của jQuery kích hoạt theo thứ tự nó bị ràng buộc :

Khi một sự kiện đạt đến một phần tử, tất cả các trình xử lý ràng buộc với loại sự kiện đó cho phần tử đó sẽ được kích hoạt. Nếu có nhiều trình xử lý được đăng ký, chúng sẽ luôn thực thi theo thứ tự mà chúng bị ràng buộc. Sau khi tất cả các trình xử lý đã thực thi, sự kiện tiếp tục dọc theo đường truyền sự kiện thông thường.

Nguồn: http://api.jquery.com/bind/

Vì các hàm khác của jQuery (ví dụ .click()) là các phím tắt cho .bind('click', handler), tôi đoán rằng chúng cũng được kích hoạt theo thứ tự chúng bị ràng buộc.


11

Bạn sẽ có thể sử dụng chuỗi để thực hiện các sự kiện theo trình tự, ví dụ:

$('#target')
  .bind('click',function(event) {
    alert('Hello!');
  })
  .bind('click',function(event) {
    alert('Hello again!');
  })
  .bind('click',function(event) {
    alert('Hello yet again!');
  });

Tôi đoán đoạn mã dưới đây đang làm như vậy

$('#target')
      .click(function(event) {
        alert('Hello!');
      })
      .click(function(event) {
        alert('Hello again!');
      })
      .click(function(event) {
        alert('Hello yet again!');
      });

Nguồn: http://www.peachpit.com/articles/article.aspx?p=1371947&seqNum=3

TFM cũng nói:

Khi một sự kiện đạt đến một phần tử, tất cả các trình xử lý ràng buộc với loại sự kiện đó cho phần tử đó sẽ được kích hoạt. Nếu có nhiều trình xử lý được đăng ký, chúng sẽ luôn thực thi theo thứ tự mà chúng bị ràng buộc. Sau khi tất cả các trình xử lý đã thực thi, sự kiện tiếp tục dọc theo đường truyền sự kiện thông thường.


1
Cả mã và bài viết đó đều không xác định thứ tự thực hiện xử lý. Vâng, đó là thứ tự ràng buộc sự kiện sẽ xảy ra, nhưng thứ tự xử lý sự kiện được gọi vẫn chưa được xác định chính thức.
Lưỡi liềm tươi

hả những gì về "Bây giờ khi sự kiện nhấp xảy ra, trình xử lý sự kiện đầu tiên sẽ được gọi, tiếp theo là lần thứ hai, tiếp theo là lần thứ ba." Không rõ ràng?
anddoutoi

và vâng, tôi biết rằng các recs chính thức không xác định điều này và PPK đã chứng minh rằng việc thực thi sự kiện là ngẫu nhiên nhưng có lẽ jQuery đã sửa lỗi này ^^
anddoutoi

Ahh, bỏ lỡ câu đó. Trong thực tế, tác giả là thông tin sai. jQuery chưa "sửa" cái này. Bởi vì thông số kỹ thuật không chính thức xác định thứ tự, về mặt kỹ thuật không có gì cần sửa.
Lưỡi liềm tươi

5
@CrescentFresh: Xin lỗi vì đã trả lời trễ như vậy, tôi chỉ thấy câu hỏi, nhưng tôi muốn bạn chỉ vào liên kết , đây là tài liệu chính thức của jQuery và nó nói rõ rằngWhen an event reaches an element, all handlers bound to that event type for the element are fired. If there are multiple handlers registered, they will always execute in the order in which they were bound. After all handlers have executed, the event continues along the normal event propagation path.
Razort4x

2

Cả hai xử lý được gọi.

Bạn có thể nghĩ về ràng buộc sự kiện nội tuyến (ví dụ "onclick=..."), trong đó một nhược điểm lớn chỉ có một trình xử lý có thể được đặt cho một sự kiện.

jQuery phù hợp với mô hình đăng ký sự kiện DOM Cấp 2 :

Mô hình sự kiện DOM cho phép đăng ký nhiều người nghe sự kiện trên một EventTarget. Để đạt được điều này, trình lắng nghe sự kiện không còn được lưu trữ dưới dạng giá trị thuộc tính


@Rich: đơn hàng chính thức không xác định.
Lưỡi liềm tươi

2

Làm cho nó hoạt động thành công bằng cách sử dụng 2 phương pháp: đóng gói của Stephan202 và nhiều trình lắng nghe sự kiện. Tôi có 3 tab tìm kiếm, hãy xác định id văn bản đầu vào của chúng trong một mảng:

var ids = new Array("searchtab1", "searchtab2", "searchtab3");

Khi nội dung của searchtab1 thay đổi, tôi muốn cập nhật searchtab2 và searchtab3. Đã làm theo cách này để đóng gói:

for (var i in ids) {
    $("#" + ids[i]).change(function() {
        for (var j in ids) {
            if (this != ids[j]) {
                $("#" + ids[j]).val($(this).val());
            }
        }
    });
}

Nhiều người nghe sự kiện:

for (var i in ids) {
    for (var j in ids) {
        if (ids[i] != ids[j]) {
            $("#" + ids[i]).change(function() {
                $("#" + ids[j]).val($(this).val());
            });
        }
    }
}

Tôi thích cả hai phương pháp, nhưng lập trình viên đã chọn đóng gói, tuy nhiên nhiều trình lắng nghe sự kiện cũng hoạt động. Chúng tôi đã sử dụng Chrome để kiểm tra nó.


1

Có một cách giải quyết để đảm bảo rằng một trình xử lý xảy ra sau một trình xử lý khác: gắn trình xử lý thứ hai vào một phần tử có chứa và để cho sự kiện nổi lên. Trong trình xử lý được đính kèm với bộ chứa, bạn có thể xem event.target và làm một cái gì đó nếu đó là thứ bạn quan tâm.

Thô, có thể, nhưng nó chắc chắn nên hoạt động.


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.