Trực tiếp so với được ủy quyền - jQuery .on ()


159

Tôi đang cố gắng hiểu sự khác biệt đặc biệt này giữa các trình xử lý sự kiện trực tiếp và được ủy nhiệm bằng phương thức jQuery .on () . Cụ thể, câu cuối cùng trong đoạn này:

Khi a selectorđược cung cấp, bộ xử lý sự kiện được gọi là ủy nhiệm . Trình xử lý không được gọi khi sự kiện xảy ra trực tiếp trên phần tử bị ràng buộc, mà chỉ dành cho con cháu (phần tử bên trong) khớp với bộ chọn. jQuery đánh bóng sự kiện từ mục tiêu sự kiện cho đến phần tử nơi trình xử lý được đính kèm (nghĩa là phần tử trong cùng với phần tử ngoài cùng) và chạy trình xử lý cho bất kỳ phần tử nào dọc theo đường dẫn đó khớp với bộ chọn.

"Chạy trình xử lý cho bất kỳ yếu tố nào" có nghĩa là gì? Tôi đã làm một trang thử nghiệm để thử nghiệm với khái niệm này. Nhưng cả hai cấu trúc sau đây dẫn đến cùng một hành vi:

$("div#target span.green").on("click", function() {
   alert($(this).attr("class") + " is clicked");
});

hoặc là,

$("div#target").on("click", "span.green", function() {
   alert($(this).attr("class") + " is clicked");
});

Có lẽ ai đó có thể tham khảo một ví dụ khác để làm rõ điểm này? Cảm ơn.


7
Dành cho tất cả những người quan tâm: jsperf.com/jquery-fn-on-delegate-vs-direct
dgo

1
@KevinWheeler Tôi đã nhận xét về câu đố của bạn bên dưới nhưng ở đây , về cơ bản, nó không được thiết lập chính xác (bạn ràng buộc với yếu tố phụ huynh và ủy thác dành cho trẻ em). Để trả lời câu hỏi của bạn, điều đó có nghĩa là trình xử lý được ủy nhiệm sẽ khớp với các phần tử mới được thêm vào, trong đó phần tử không có ủy nhiệm sẽ không. Phái đoàn có lợi ích là có ít sự kiện được nối vào trình duyệt khiến mức tiêu thụ bộ nhớ cho ứng dụng thấp hơn, tuy nhiên sự đánh đổi là nó tăng thời gian xử lý một lần nhấp (tối thiểu). Nếu bạn đang làm một trò chơi, đừng ủy thác.
vipero07

1
"Trang thử nghiệm" mà bạn tham khảo không hoạt động.
Jaime Montoya

Câu trả lời:


373

Trường hợp 1 (trực tiếp):

$("div#target span.green").on("click", function() {...});

== Này! Tôi muốn mọi span.green bên trong div # target lắng nghe: khi bạn được nhấp vào, hãy thực hiện X.

Trường hợp 2 (được ủy quyền):

$("div#target").on("click", "span.green", function() {...});

== Này, div # mục tiêu! Khi bất kỳ yếu tố con nào của bạn là "span.green" được nhấp, hãy thực hiện X với chúng.

Nói cách khác...

Trong trường hợp 1, mỗi nhịp đều được hướng dẫn riêng. Nếu các nhịp mới được tạo, họ sẽ không nghe hướng dẫn và sẽ không trả lời các nhấp chuột. Mỗi nhịp chịu trách nhiệm trực tiếp cho các sự kiện riêng của mình.

Trong trường hợp 2, chỉ có container đã được hướng dẫn; nó chịu trách nhiệm nhận thấy các nhấp chuột thay mặt cho các yếu tố con của nó. Công việc đánh bắt sự kiện đã được ủy quyền . Điều này cũng có nghĩa là hướng dẫn sẽ được thực hiện cho các phần tử con được tạo trong tương lai.


45
Đó là một lời giải thích tuyệt vời, và đã mang lại sự rõ ràng cho một vấn đề mà từ lâu tôi đã từ chối hiểu. Cảm ơn!
dgo

3
Vậy tại sao lại on()cho phép hai đối số khi điều đó khá giống với việc sử dụng click()?
nipponese

5
.on () là API mục đích chung có thể xử lý bất kỳ loại sự kiện nào, bao gồm nhiều sự kiện khác nhau (bạn có thể đặt nhiều tên sự kiện trong chuỗi đầu tiên đó.) .click () chỉ là cách viết tắt cho hình thức đầu tiên đó.
N3dst4

1
@newbie, @ N3dst4: e.targetsẽ là mục tiêu ban đầu của sự kiện nhấp chuột (có thể là nút con nếu span.greencó con). Từ bên trong xử lý, bạn nên sử dụng thistài liệu tham khảo. Xem câu đố này .
LeGEC

1
Một lưu ý khác để thêm vào chủ đề của phái đoàn - cả hai đều rất hữu ích và rất hiệu quả. Bạn sẽ sử dụng ít tài nguyên trình duyệt hơn với ủy quyền so với việc đính kèm một sự kiện vào mọi yếu tố phù hợp. Tôi nghĩ tôi sẽ đề cập đến nó, chỉ trong trường hợp mọi người cần thêm lý do để sử dụng ủy quyền.
phatskat

6

Cách thứ nhất, $("div#target span.green").on()liên kết một trình xử lý nhấp chuột trực tiếp với (các) nhịp khớp với bộ chọn tại thời điểm mã được thực thi. Điều này có nghĩa là nếu các nhịp khác được thêm vào sau (hoặc lớp của chúng thay đổi để khớp) thì chúng đã bỏ lỡ và sẽ không có trình xử lý nhấp chuột. Điều đó cũng có nghĩa là nếu sau đó bạn loại bỏ lớp "xanh" khỏi một trong các nhịp thì trình xử lý nhấp chuột của nó sẽ tiếp tục chạy - jQuery không theo dõi cách trình xử lý được gán và kiểm tra xem liệu bộ chọn có còn khớp không.

Cách thứ hai $("div#target").on(), liên kết một trình xử lý nhấp chuột với (các) div khớp (một lần nữa, điều này chống lại các đối sánh khớp tại thời điểm đó), nhưng khi một nhấp chuột xảy ra ở đâu đó trong hàm div, trình xử lý sẽ chỉ được chạy nếu nhấp chuột xảy ra không chỉ trong div mà trong một phần tử con khớp với bộ chọn trong tham số thứ hai .on(), "span.green". Thực hiện theo cách này không thành vấn đề khi các nhịp con đó được tạo, nhấp vào chúng vẫn sẽ chạy trình xử lý.

Vì vậy, đối với một trang không tự động thêm hoặc thay đổi nội dung của trang, bạn sẽ không nhận thấy sự khác biệt giữa hai phương pháp. Nếu bạn đang tự động thêm các phần tử con bổ sung, cú pháp thứ hai có nghĩa là bạn không phải lo lắng về việc gán các trình xử lý nhấp chuột cho chúng vì bạn đã thực hiện nó một lần cho cha mẹ.


5

Giải thích về N3dst4 là hoàn hảo. Dựa trên điều này, chúng ta có thể giả định rằng tất cả các yếu tố con nằm trong cơ thể, do đó chúng ta chỉ cần sử dụng điều này:

$('body').on('click', '.element', function(){
    alert('It works!')
});

Nó hoạt động với sự kiện trực tiếp hoặc đại biểu.


2
jquery khuyên không nên sử dụng cơ thể, vì nó chậm hơn, bởi vì kịch bản sẽ phải tìm kiếm tất cả trẻ em bên trong cơ thể, điều này sẽ rất nhiều trong hầu hết các trường hợp. Tốt hơn (nhanh hơn) để sử dụng bộ chứa cha mẹ ngay lập tức của phần tử.
mikeoft

1
Jquery đã loại bỏ phương thức trực tiếp đang làm giống như bạn đã chỉ ra. Đây là hiệu suất yếu và không nên được sử dụng.
Maciej Sikora

Trong các trình duyệt hiện đại, $('body').on()ủy nhiệm từ .elementnên hành xử giống hệt như bản địa document.body.addEventHandler()với một if (Event.target.className.matches(/\belement\b/))trong cuộc gọi lại. Nó có thể chậm hơn một chút trong jquery do $.proxytrên đầu nhưng đừng trích dẫn tôi về điều đó.
cowbert

2

Tiếp tuyến với OP, nhưng khái niệm giúp tôi làm sáng tỏ sự nhầm lẫn với tính năng này là các yếu tố bị ràng buộc phải là cha mẹ của các yếu tố được chọn .

  • Giới hạn đề cập đến những gì còn lại của .on.
  • Được chọn đề cập đến đối số thứ 2 của .on().

Phân quyền không hoạt động như .find (), chọn một tập hợp con của các phần tử ràng buộc. Bộ chọn chỉ áp dụng cho các yếu tố con nghiêm ngặt.

$("span.green").on("click", ...

rất khác với

$("span").on("click", ".green", ...

Cụ thể, để đạt được những lợi thế @ N3dst4 gợi ý với "các yếu tố được tạo ra trong tương lai", yếu tố ràng buộc phải là cha mẹ vĩnh viễn . Sau đó, những đứa trẻ được chọn có thể đến và đi.

BIÊN TẬP

Danh sách kiểm tra tại sao ủy thác .onkhông hoạt động

Lý do rắc rối tại sao $('.bound').on('event', '.selected', some_function)có thể không hoạt động:

  1. Yếu tố ràng buộc không phải là vĩnh viễn . Nó được tạo ra sau khi gọi.on()
  2. Phần tử được chọn không phải là phần tử con của phần tử ràng buộc. Đó là cùng một yếu tố.
  3. Phần tử được chọn đã ngăn chặn sự sủi bọt của một sự kiện đến phần tử bị ràng buộc bằng cách gọi .stopPropagation().

(Bỏ qua các lý do ít khó khăn hơn, chẳng hạn như bộ chọn sai chính tả.)


1

Tôi sẽ đăng một bài với sự so sánh các sự kiện trực tiếp và được ủy quyền. Tôi so sánh js thuần nhưng nó có cùng ý nghĩa với jquery chỉ gói gọn nó.

Kết luận là việc xử lý sự kiện được ủy nhiệm dành cho cấu trúc DOM động nơi các phần tử được liên kết có thể được tạo trong khi người dùng tương tác với trang (không cần liên kết lại) và xử lý sự kiện trực tiếp dành cho các phần tử DOM tĩnh, khi chúng ta biết rằng cấu trúc đó sẽ không thay đổi.

Để biết thêm thông tin và so sánh đầy đủ - http://maciejsikora.com/stiteria-events-vs-event-delegation/

Sử dụng các trình xử lý luôn được ủy nhiệm, mà tôi thấy hiện tại rất hợp thời trang là không đúng cách, nhiều lập trình viên sử dụng nó vì "nó nên được sử dụng", nhưng sự thật là các trình xử lý sự kiện trực tiếp tốt hơn cho một số trường hợp và lựa chọn sử dụng phương pháp nào nên được hỗ trợ bởi kiến ​​thức về sự khác biệt.


nếu gắn nhiều trình xử lý sự kiện (ví dụ: mỗi hàng của một bảng), thì nên sử dụng trình xử lý được ủy nhiệm duy nhất để chứa thay vì gắn nhiều trình xử lý trực tiếp. Bạn có thể thấy điều này từ thực tế cơ bản rằng số lượng xử lý sự kiện tự nó là một số liệu định hình.
cowbert
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.