jQuery provides .bind(), .live(), and .delegate() methods for binding and delegated events. This article discusses the internal implementation of these methods and shows their advantages, disadvantages and applicable occasions.
Event delegation
Examples of event delegation abound in reality. For example, three colleagues are expected to receive express delivery on Monday. There are two ways to sign for the express delivery: one is to have three people waiting for the express delivery at the door of the company; the other is to entrust the receptionist to sign for it on your behalf. In reality, we mostly use the entrusted solution (the company will not tolerate so many employees standing at the door just waiting for express delivery). After the MM at the front desk receives the express delivery, she will determine who the recipient is, then sign for it according to the recipient's requirements, and even pay for it on her behalf. Another advantage of this solution is that even if new employees come to the company (no matter how many), the front desk MM will verify the express delivery sent to the new employees and sign for it on their behalf.
We know that when the DOM dispatches an event to each element in the page, the corresponding element generally handles the event in the event bubbling stage. In a structure like body > div > a, if you click the a element, the click event will bubble up from a to the div and body (i.e. the document object). Therefore, click events that occur on a, div and body elements can also be handled. By using the mechanism of event propagation (here, bubbling), event delegation can be achieved. Specifically, event delegation means that the event target does not process the event itself, but delegates the processing task to its parent element or ancestor element, or even the root element (document).
.bind()
Suppose there is a table with multiple rows and columns. We want the user to click on each cell to see more information related to the content in it. information (e.g., via a tooltip). To do this, you can bind a click event to each cell:
$("info_table td").bind("click", function(){/*Show more information*/});
The problem is that if there are 10 columns and 500 rows in the table to which click events are bound, then finding and traversing 5000 cells will cause the script to execute significantly slower, while saving 5000 td elements and corresponding The event handler will also take up a lot of memory (similar to having everyone physically stand at the door waiting for a delivery).
Based on the previous example, if we want to implement a simple photo album application, each page only displays thumbnails of 50 photos (50 cells), and the user clicks "Page x" (or "Next Page") link can dynamically load another 50 photos from the server via Ajax. In this case, it seems that binding events for 50 cells using the .bind() method is acceptable again.
That’s not the case. Using the .bind() method will only bind click events to 50 cells on the first page. Cells in subsequent pages that are dynamically loaded will not have this click event. In other words, .bind() can only bind events to elements that already exist when it is called, and cannot bind events to elements that will be added in the future (similar to how new employees cannot receive express delivery).
Event delegation can solve the above two problems. Specific to the code, just use the .live() method added in jQuery 1.3 instead of the .bind() method:
$("#info_table td").live("click",function() {/*Show more information*/});
The .live() method here will bind the click event to the $(document) object (but this cannot be reflected from the code, this is also An important reason why the .live() method has been criticized (will be discussed in detail later), and you only need to bind $(document) once (not 50 times, let alone 5000 times), and then you can handle subsequent dynamic loading. Click event of the photo cell. When receiving any event, the $(document) object will check the event type and event target. If it is a click event and the event target is td, then the handler delegated to it will be executed.
.live()
So far, everything seems to be perfect. Unfortunately, this is not the case. Because the .live() method is not perfect, it has the following major shortcomings: The
$() function will find all td elements in the current page and create jQuery objects, but it is not used when confirming the event target. This collection of td elements instead uses selector expressions to compare with event.target or its ancestor elements, so generating this jQuery object will cause unnecessary overhead;
The event is bound to the $(document) element by default. If the DOM nested structure is very deep, event bubbling through a large number of ancestor elements will cause performance losses;
can only be placed after the directly selected element, and cannot be used after the consecutive DOM traversal method, that is, $("#infotable td ").live... works, but $("#infotable").find("td").live... does not work;
collects td elements and creates jQuery objects, but the actual operation is $( document) object, which is puzzling.
Solution
In order to avoid generating unnecessary jQuery objects, you can use a hack called "early delegation", that is, in $(document).ready () method external call .live():
PS:(참고: 이 글은 "JQuery Basics Tutorial (3rd Edition)"의 관련 장을 바탕으로 작성되었으며jQuery 1.7 Beta 1 릴리스 노트에 따르면 .bind(), .live() 및 .delegate()의 공존으로 인해 발생하는 불일치 문제를 해결하기 위해 jQuery 1.7에서는 새로운 이벤트 메소드인 .on() 및 .off()를 추가합니다: $(elems).on(events, selector, data, fn);
$(elems).off(events, selector, fn) );
selector를 지정하면 이벤트 위임이고, 그렇지 않으면 일반 바인딩입니다. 이전 API와 새 API 간의 대응은 다음과 같습니다.
도 참조합니다.