Sự khác biệt giữa các hàm `click`,` bind`, `live`,` ủy nhiệm`, `trigger` và` on` (với một ví dụ)?


139

Tôi đã đọc tài liệu của từng chức năng trên jQuery official website, nhưng không có danh sách so sánh như vậy giữa các chức năng dưới đây:

$().click(fn)
$().bind('click',fn)
$().live('click',fn)
$().delegate(selector, 'click', fn)
$().trigger('click') // UPDATED
$().on('click', selector ,fn); // more UPDATED

Xin vui lòng tránh bất kỳ liên kết tham khảo.

Làm thế nào để tất cả các chức năng trên hoạt động chính xác và nên được ưu tiên trong tình huống nào?

Lưu ý: Nếu có bất kỳ chức năng nào khác có cùng chức năng hoặc cơ chế, thì hãy giải thích.

Cập nhật

Tôi cũng đã thấy một $.triggerchức năng. Nó hoạt động tương tự như các chức năng trên?

Cập nhật thêm

Bây giờ .onđược thêm vào v1.7 và tôi nghĩ rằng cái này bằng cách nào đó bao gồm tất cả các yêu cầu chức năng trên với nhau.


3
@ Tôi cũng giống như PHP, đôi khi mọi người bỏ phiếu nếu họ không cảm thấy đó là một câu hỏi không thể trả lời bằng hướng dẫn hoặc dường như là một câu hỏi bài tập về nhà. đừng lo lắng, những người khác sẽ bỏ phiếu nếu họ thấy nó hữu ích.
typeoneerror

@ Typeoneerror - Cảm ơn bạn đã hỗ trợ, tôi đã đọc hướng dẫn và khi tôi không hiểu sự khác biệt rõ ràng thì tôi đăng ở đây.
diEcho

3
@I Like PHP - Đã chỉnh sửa câu hỏi để dọn dẹp ... điều này thường được hỏi nhưng hiếm khi theo cách này, nó có thể dễ dàng trở thành một tài nguyên có giá trị của google. Tôi đồng ý một mục wiki-ish của một cái gì đó như thế này sẽ rất hữu ích, tôi thấy sự nhầm lẫn xung quanh vấn đề này, đặc biệt là với .live().delegate()hầu như mỗi ngày, +1 cho một câu hỏi hoàn toàn hợp lệ.
Nick Craver

@Nick Craver Cảm ơn bạn đã chỉnh sửa, thực sự tôi rất tệ trong tiếng Anh (lol). Có bất kỳ maunal / tài liệu tham khảo mà làm thế nào để chúng tôi gửi một câu hỏi trên SO. Nếu nó chỉ đến bằng kinh nghiệm
diEcho

@ Tôi thích PHP - Đó là một chút của cả hai, có một Câu hỏi thường gặp tuyệt vời cho SO ở đây: meta.stackexchange.com/questions/7931 Đối với các cụm từ / nhận xét, bạn chỉ cần bắt đầu tìm hiểu những gì phù hợp và là cách tốt nhất để đôi khi truyền đạt suy nghĩ của bạn, mã> bất kỳ mô tả nào, sử dụng từ khóa phù hợp, gắn thẻ phù hợp, chỉ cần bạn ở đây lâu hơn tôi cho rằng, tôi thấy rất nhiều áp phích cải thiện theo thời gian. Đối với chỉnh sửa của bạn, .trigger()chỉ cần gọi trình xử lý sự kiện ... Tôi sẽ thêm một mô tả vào câu trả lời của tôi dưới đây.
Nick Craver

Câu trả lời:


162

Trước khi bạn đọc điều này, hãy kéo danh sách các sự kiện này lên trên một trang khác, bản thân API rất hữu ích và tất cả những gì tôi đang thảo luận dưới đây được liên kết trực tiếp từ trang này .

Đầu tiên, theo .click(function)nghĩa đen là một phím tắt cho .bind('click', function), chúng là tương đương. Sử dụng chúng khi liên kết một trình xử lý trực tiếp với một phần tử , như thế này:

$(document).click(function() {
  alert("You clicked somewhere in the page, it bubbled to document");
});

Nếu phần tử này được thay thế hoặc vứt đi, trình xử lý này sẽ không còn ở đó nữa. Ngoài ra các phần tử không có ở đó khi mã này được chạy để đính kèm trình xử lý (ví dụ: bộ chọn tìm thấy nó sau đó) sẽ không nhận được trình xử lý.

.live().delegate()có liên quan tương tự nhau, .delegate()thực sự sử dụng .live()nội bộ, cả hai đều lắng nghe các sự kiện để bong bóng. Điều này làm việc cho các yếu tố mới và cũ , họ bong bóng các sự kiện theo cùng một cách. Bạn sử dụng những thứ này khi các yếu tố của bạn có thể thay đổi, ví dụ: thêm các hàng mới, liệt kê các mục, v.v. Nếu bạn không có cha mẹ / tổ tiên chung sẽ ở lại trang và không bị thay thế tại bất kỳ thời điểm nào, hãy sử dụng .live(), như sau:

$(".clickAlert").live('click', function() {
  alert("A click happened");
});

Tuy nhiên, nếu bạn có một phần tử cha mẹ ở đâu đó không được thay thế (vì vậy các trình xử lý sự kiện của nó sẽ không tạm biệt), bạn nên xử lý nó .delegate(), như thế này:

$("#commonParent").delegate('.clickAlert', 'click', function() {
  alert("A click happened, it was captured at #commonParent and this alert ran");
});

Điều này hoạt động gần giống như .live(), nhưng sự kiện bong bóng ít lần hơn trước khi bị bắt và xử lý. Một cách sử dụng phổ biến khác của cả hai trường hợp này là lớp của bạn thay đổi trên một phần tử, không còn phù hợp với bộ chọn mà bạn đã sử dụng ban đầu ... với các phương thức này, bộ chọn được đánh giá tại thời điểm diễn ra sự kiện , nếu nó phù hợp, trình xử lý sẽ chạy .. .như phần tử không còn phù hợp với bộ chọn nữa, nó sẽ không thực thi nữa. Với .click()Tuy nhiên, xử lý sự kiện là ràng buộc ngay trên phần tử DOM, thực tế là nó không phù hợp với bất cứ điều gì chọn được sử dụng để tìm thấy nó là không thích hợp ... sự kiện này được ràng buộc và nó ở lại cho đến khi yếu tố đó đã biến mất, hoặc xử lý được gỡ bỏ thông qua .unbind().

Một cách sử dụng phổ biến khác cho .live().delegate()hiệu suất . Nếu bạn đang xử lý nhiều yếu tố, việc gắn trình xử lý nhấp trực tiếp vào từng yếu tố sẽ tốn kém và mất thời gian. Trong những trường hợp này sẽ kinh tế hơn khi thiết lập một trình xử lý duy nhất và để bong bóng thực hiện công việc, hãy xem câu hỏi này nơi nó tạo ra sự khác biệt lớn , đó là một ví dụ tốt về ứng dụng.


Kích hoạt - cho câu hỏi cập nhật

Có 2 chức năng kích hoạt trình xử lý sự kiện chính khả dụng, chúng thuộc cùng loại "Đính kèm Trình xử lý sự kiện" trong API , đó là .trigger().triggerHandler(). .trigger('eventName')có một số phím tắt được tích hợp sẵn cho các sự kiện phổ biến, ví dụ:

$().click(fn); //binds an event handler to the click event
$().click();   //fires all click event handlers for this element, in order bound

Bạn có thể xem một danh sách bao gồm các phím tắt ở đây .

Đối với sự khác biệt, .trigger()kích hoạt trình xử lý sự kiện (nhưng không phải là hành động mặc định hầu hết thời gian, ví dụ: đặt con trỏ ở vị trí bên phải trong một lần nhấp <textarea>). Nó làm cho các trình xử lý sự kiện xảy ra theo thứ tự mà chúng bị ràng buộc (như sự kiện gốc sẽ xảy ra), kích hoạt các hành động sự kiện riêng và làm nổi lên DOM.

.triggerHandler()thường là cho một mục đích khác, ở đây bạn chỉ đang cố gắng xử lý (các) trình xử lý bị ràng buộc, nó không gây ra sự kiện bản địa để kích hoạt, ví dụ như gửi biểu mẫu. Nó không làm bong bóng DOM và nó không thể kết nối được (nó trả về bất cứ thứ gì xử lý sự kiện ràng buộc cuối cùng cho sự kiện đó trả về). Ví dụ: nếu bạn muốn kích hoạt một focussự kiện nhưng không thực sự tập trung vào đối tượng, bạn chỉ muốn mã bạn bị ràng buộc .focus(fn)để chạy, điều này sẽ làm điều đó, trong khi đó .trigger()sẽ làm điều đó cũng như thực sự tập trung vào phần tử và bong bóng.

Đây là một ví dụ thực tế:

$("form").submit(); //actually calling `.trigger('submit');`

Điều này sẽ chạy bất kỳ trình xử lý gửi nào, ví dụ như trình cắm xác thực jQuery , sau đó thử gửi <form>. Tuy nhiên, nếu bạn chỉ muốn xác thực, vì nó được kết nối thông qua một submittrình xử lý sự kiện, nhưng không gửi <form>sau đó, bạn có thể sử dụng .triggerHandler('submit'), như thế này:

$("form").triggerHandler('submit');

Plugin ngăn trình xử lý gửi biểu mẫu bằng cách bỏ qua nếu kiểm tra xác thực không vượt qua, nhưng với phương pháp này, chúng tôi không quan tâm nó làm gì. Cho dù nó có bị hủy bỏ hay không, chúng tôi không cố gắng gửi biểu mẫu, chúng tôi chỉ muốn kích hoạt nó để xác thực lại và không làm gì khác. ( Tuyên bố miễn trừ trách nhiệm: Đây là một ví dụ không cần thiết vì có một .validate()phương thức trong plugin, nhưng đó là một minh họa rõ ràng về ý định)


Rất kỹ lưỡng. Một điều chỉnh nhỏ: triggerkhông kích hoạt một sự kiện bản địa. Theo bản địa tôi có nghĩa là một sự kiện được mô phỏng với fireEvent(IE) hoặc dispatchEvent(w3c).
Lưỡi liềm tươi

@Crescent - Được cập nhật để ít mơ hồ hơn, ý tôi là nó kích hoạt các hành động sự kiện gốc , như gửi biểu mẫu, liên kết theo sau, v.v ... hy vọng bản cập nhật rõ ràng hơn :)
Nick Craver

@Nick từ những gì tôi đang đọc, có vẻ như bạn nhận live()được khác với những gì bạn đã đưa cho tôi ở đây: stackoverflow.com/questions/3981762/ chủ đề 'trọng lượng' vẫn còn là một mối quan tâm khi sử dụng live()?
Yahel

@yahelc - Vâng, tất nhiên ... câu trả lời này hoàn toàn so sánh các tùy chọn của người xử lý sự kiện và mục đích cụ thể của họ. Chi phí trọng lượng so với số lượng ràng buộc ban đầu so với nếu bạn thêm bất cứ thứ gì một cách linh hoạt so với bộ chọn ban đầu vẫn là những mối quan tâm hợp lệ. Nếu bạn cấu trúc trang đang không phải là rằng lớn bạn bạn không phải sự kiện nhiều thì bạn đang sử dụng tốt ... những lo ngại về trọng lượng là tỷ lệ thuận với kích thước / độ sâu của cấu trúc của bạn và số lượng các sự kiện (của loại .live()cuộc gọi của bạn lắng nghe, ví dụ click) đang được tạo, vì nó chạy bộ chọn cho từng cuộc gọi.
Nick Craver

1
trong jQuery 1.7, live () không được dùng cho $ (document) .on ().
Synchro

28

Hai cái đầu tương đương nhau.

// The following two statements do the same thing:
$("blah").click( function() { alert( "Click!" ); } );
$("blah").bind( "click", function() { alert( "Click!" ); } ); 

Tuy nhiên, cái thứ hai có thể được sử dụng để liên kết với nhiều sự kiện cùng một lúc, bằng cách chỉ định một số tên sự kiện được phân tách bằng dấu cách:

$("blah").bind( "click mouseover mouseout", function() { alert( "Click! Or maybe mouse moved." ); } ); 

Các .livephương pháp là thú vị hơn. Hãy xem xét ví dụ sau:

<a class="myLink">A link!</a>
<a id="another">Another link!</a>

<script>
    $("a.myLink").click( function() { alert( 'Click!' ); } );

    $("a#another").addClass( "myLink" );
</script>

Sau khi dòng thứ hai của tập lệnh thực thi, liên kết thứ hai cũng sẽ có một lớp CSS "myLink". Nhưng nó sẽ không có trình xử lý sự kiện, vì nó không có lớp khi sự kiện được đính kèm.

Bây giờ hãy xem xét bạn muốn nó theo cách khác: mỗi khi một liên kết với lớp "myLink" xuất hiện ở đâu đó trên trang, bạn muốn nó tự động có trình xử lý sự kiện tương tự. Điều này rất phổ biến khi bạn có một số loại danh sách hoặc bảng, trong đó bạn thêm các hàng hoặc ô một cách linh hoạt, nhưng muốn tất cả chúng hoạt động theo cùng một cách. Thay vì đi đến tất cả nỗi đau của việc chỉ định xử lý sự kiện một lần nữa, bạn có thể sử dụng .livephương pháp:

<a class="myLink">A link!</a>
<a id="another">Another link!</a>

<script>
    $("a.myLink").live( "click", function() { alert( 'Click!' ); } );

    $("a#another").addClass( "myLink" );
</script>

Trong ví dụ này, liên kết thứ hai cũng sẽ nhận được trình xử lý sự kiện ngay khi nó nhận được lớp "myLink". Ma thuật! :-)

Tất nhiên, nó không phải theo nghĩa đen. Điều .livethực sự làm là gắn trình xử lý không phải vào chính phần tử được chỉ định, mà là chính gốc của cây HTML (phần tử "cơ thể"). Các sự kiện trong DHTML có tính năng "vui nhộn" này. Xem xét điều này:

<div> <a> <b>text</b> </a> </div>

Nếu bạn nhấp vào "văn bản", trước tiên, phần tử <b> sẽ nhận được sự kiện "nhấp chuột". Sau đó, phần tử <a> sẽ nhận được sự kiện "nhấp chuột". Và sau đó, phần tử <div> sẽ nhận được sự kiện "nhấp chuột". Và như vậy - tất cả các cách đến phần tử <body>. Và đó là nơi jQuery sẽ nắm bắt sự kiện và xem liệu có bất kỳ trình xử lý "trực tiếp" nào áp dụng cho phần tử gây ra sự kiện đó ngay từ đầu không. Khéo léo!

Và cuối cùng là .delegatephương pháp. Nó chỉ đơn giản là đưa tất cả các phần tử con của bạn phù hợp với bộ chọn đã cho và đính kèm một trình xử lý "sống" cho chúng. Hãy xem:

$("table").delegate( "td", "click", function() { alert( "Click!" ); } );

// Is equivalent to:
$("table").each( function() {
    $(this).find( "td" ).live( "click", function() { alert( "Click!" ); } );
} );

Câu hỏi?


Để chính xác, .live()liên kết với documentkhông <body>:) Bạn có thể xem bản demo tại đây, chỉ cần kéo bảng điều khiển lên để kiểm tra: jsfiddle.net/aJy2B
Nick Craver

3
Nó thuận tiện hơn để giải thích nó theo cách này. :-)
Fyodor Soikin

4
Đủ công bằng trên phần "cơ thể", nhưng "tất cả các cách của phần tử <body>" đều sai, các sự kiện tiếp tục trôi qua ở đó và không phải là nơi .live()xử lý, nó ở trên đó, trên document:) Bạn có thể thấy bản demo của cái này ở đây: jsfiddle.net/S2VBX
Nick Craver

8

Kể từ jQuery 1.7, phương thức .live () không được dùng nữa. Nếu bạn đang sử dụng phiên bản jQuery <1.7 thì chính thức khuyến nghị sử dụng .delegate () trên .live ().

.live () hiện đã được thay thế bằng .on ().

Tốt nhất nên truy cập trực tiếp vào trang jQuery để biết thêm thông tin, nhưng đây là các phiên bản hiện tại của phương thức .on ():

.on( events [, selector] [, data], handler(eventObject) )
.on( events-map [, selector] [, data] )

http://api.jquery.com/on/


2

$().click(fn)$().bind('click', fn)giống hệt nhau từ cái nhìn đầu tiên, nhưng $.bindphiên bản mạnh hơn vì hai lý do:

  1. $().bind()cho phép bạn gán một trình xử lý cho nhiều sự kiện, ví dụ , $().bind('click keyup', fn).
  2. $().bind()chỉ hỗ trợ các sự kiện được đặt tên - một tính năng mạnh mẽ nếu bạn muốn loại bỏ (hủy liên kết) chỉ một số trình xử lý sự kiện nhất định mà một phần tử bị ràng buộc - đọc thêm trong Sự kiện không gian tên .

Live vs đại biểu: điều này đã được trả lời trong các câu trả lời khác.


1

Đây là nơi đọc API có thể giúp đỡ. Tuy nhiên, tôi biết trên đỉnh đầu của mình, vì vậy bạn có thể tiếp tục lười biếng (yay!).

$('#something').click(fn);
$('#something').bind('click',fn);

Không có sự khác biệt ở đây (mà tôi biết). .clickchỉ đơn giản là một phương thức tiện lợi / trợ giúp để.bind('click'

// even after this is called, all <a>s in
// <div class="dynamic_els"> will continue
// to be assigned these event handlers

$('div.dynamic_els a').live(‘click’,fn);

Điều này rất khác nhau, khi .livethêm các sự kiện vào bộ chọn mà bạn truyền vào (mà bạn chưa có ở đây) và tiếp tục xem xét DOM khi các nút được chèn / xóa

$('#some_element').delegate('td','click',fn);

Điều này chỉ khác nhau vì cách bạn chỉ định xử lý sự kiện. .delegateđược tập trung vào bong bóng sự kiện DOM. Nguyên tắc cơ bản là tất cả các sự kiện bong bóng lên trên qua cây DOM cho đến khi nó đạt đến phần tử gốc ( documenthay windowhay <html>hay <body>, tôi không thể nhớ chính xác).

Dù bằng cách nào, bạn đang ràng buộc một onclicktrình xử lý với tất cả các <td>s bên trong $('#some_element')(bạn phải chỉ định một bộ chọn, mặc dù bạn có thể nói $(document)). Khi một trong những đứa con của nó được bấm, sự kiện sẽ nổi lên <td>. Sau đó, bạn có thể trích xuất phần tử nguồn của sự kiện (mà jQuery thực hiện cho bạn một cách tự động).

Điều này hữu ích khi có rất nhiều yếu tố và bạn chỉ có một vài (hoặc một điểm trung tâm) mà những sự kiện này sẽ trải qua. Điều này giúp tiết kiệm công sức và bộ nhớ của trình duyệt để hợp nhất các trình xử lý sự kiện này thành các đối tượng ít hơn.


1
.live() cũng hoạt động với bong bóng sự kiện, trên thực tế .delegate()là một trình bao bọc .live(), nó chỉ cần thêm một bối cảnh và ràng buộc với một yếu tố khác hơn là documentđể chụp các bong bóng. Tôi nghĩ rằng sự hiểu biết của bạn về cách các trình xử lý sủi bọt hoạt động hơi sai (đây là khía cạnh thường bị hiểu lầm nhất của jQuery 1.4 tôi nghĩ). Trình xử lý chỉ dựa trên phần tử mà bạn ràng buộc với nó, vì vậy bất kỳ phần tử nào bạn gọi .delegate()hoặc documenttrong trường hợp .live(), khi một sự kiện bong bóng đến đó, nó sẽ kiểm tra mục tiêu để xem nó có khớp với bộ chọn hay không và nếu nó thực thi.
Nick Craver
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.