admin管理员组

文章数量:1134591

I am trying to understand this particular difference between the direct and delegated event handlers using the jQuery .on() method. Specifically, the last sentence in this paragraph:

When a selector is provided, the event handler is referred to as delegated. The handler is not called when the event occurs directly on the bound element, but only for descendants (inner elements) that match the selector. jQuery bubbles the event from the event target up to the element where the handler is attached (i.e., innermost to outermost element) and runs the handler for any elements along that path matching the selector.

What does it mean by "runs the handler for any elements"? I made a test page to experiment with the concept. But both following constructs lead to the same behavior:

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

or,

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

Maybe someone could refer to a different example to clarify this point? Thanks.

I am trying to understand this particular difference between the direct and delegated event handlers using the jQuery .on() method. Specifically, the last sentence in this paragraph:

When a selector is provided, the event handler is referred to as delegated. The handler is not called when the event occurs directly on the bound element, but only for descendants (inner elements) that match the selector. jQuery bubbles the event from the event target up to the element where the handler is attached (i.e., innermost to outermost element) and runs the handler for any elements along that path matching the selector.

What does it mean by "runs the handler for any elements"? I made a test page to experiment with the concept. But both following constructs lead to the same behavior:

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

or,

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

Maybe someone could refer to a different example to clarify this point? Thanks.

Share Improve this question edited Sep 6, 2016 at 14:13 RPichioli 3,3353 gold badges26 silver badges31 bronze badges asked Nov 13, 2011 at 10:26 moeymoey 10.9k25 gold badges72 silver badges112 bronze badges 3
  • 7 For all interested: jsperf.com/jquery-fn-on-delegate-vs-direct – dgo Commented Apr 7, 2015 at 16:25
  • 1 @KevinWheeler I commented on your fiddle below but here, essentially it isn't set up correctly (you are binding to the parent element, and delegation is intended for the children). To answer your question moey it means that the delegated handler will match newly added elements, where the one without delegation won't. Delegation has the benefit of there being less events hooked into the browser causing lower memory consumption for the app, however the tradeoff is it increases the time to process a click (minimally). If you are making a game don't delegate. – vipero07 Commented Jun 19, 2015 at 21:47
  • 1 The "test page" you reference is not working. – Jaime Montoya Commented Sep 11, 2017 at 21:52
Add a comment  | 

6 Answers 6

Reset to default 397

Case 1 (direct):

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

== Hey! I want every span.green inside div#target to listen up: when you get clicked on, do X.

Case 2 (delegated):

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

== Hey, div#target! When any of your child elements which are "span.green" get clicked, do X with them.

In other words...

In case 1, each of those spans has been individually given instructions. If new spans get created, they won't have heard the instruction and won't respond to clicks. Each span is directly responsible for its own events.

In case 2, only the container has been given the instruction; it is responsible for noticing clicks on behalf of its child elements. The work of catching events has been delegated. This also means that the instruction will be carried out for child elements that are created in future.

The first way, $("div#target span.green").on(), binds a click handler directly to the span(s) that match the selector at the moment that code is executed. This means if other spans are added later (or have their class changed to match) they have missed out and will not have a click handler. It also means if you later remove the "green" class from one of the spans its click handler will continue to run - jQuery doesn't keep track of how the handler was assigned and check to see if the selector still matches.

The second way, $("div#target").on(), binds a click handler to the div(s) that match (again, this is against those that match at that moment), but when a click occurs somewhere in the div the handler function will only be run if the click occurred not just in the div but in a child element matching the selector in the second parameter to .on(), "span.green". Done this way it doesn't matter when those child spans were created, clicking upon them will still run the handler.

So for a page that isn't dynamically adding or changing its contents you won't notice a difference between the two methods. If you are dynamically adding extra child elements the second syntax means you don't have to worry about assigning click handlers to them because you've already done it once on the parent.

The explanation of N3dst4 is perfect. Based on this, we can assume that all child elements are inside body, therefore we need use only this:

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

It works with direct or delegate event.

Tangential to the OP, but the concept that helped me unravel confusion with this feature is that the bound elements must be parents of the selected elements.

  • Bound refers to what is left of the .on.
  • Selected refers to the 2nd argument of .on().

Delegation does not work like .find(), selecting a subset of the bound elements. The selector only applies to strict child elements.

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

is very different from

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

In particular, to gain the advantages @N3dst4 hints at with "elements that are created in future" the bound element must be a permanent parent. Then the selected children can come and go.

EDIT

Checklist of why delegated .on doesn't work

Tricky reasons why $('.bound').on('event', '.selected', some_function) may not work:

  1. Bound element is not permanent. It was created after calling .on()
  2. Selected element is not a proper child of a bound element. It's the same element.
  3. Selected element prevented bubbling of an event to the bound element by calling .stopPropagation().

(Omitting less tricky reasons, such as a misspelled selector.)

I wro te a post with a comparison of direct events and delegated. I compare pure js but it has the same meaning for jquery which only encapsulate it.

Conclusion is that delegated event handling is for dynamic DOM structure where binded elements can be created while user interact with page ( no need again bindings ), and direct event handling is for static DOM elements, when we know that structure will not change.

For more information and full comparison - http://maciejsikora.com/standard-events-vs-event-delegation/

Using always delegated handlers, which I see is current very trendy is not right way, many programmers use it because "it should be used", but truth is that direct event handlers are better for some situation and the choice which method use should be supported by knowledge of differences.

Case 3 (delegated):

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

本文标签: javascriptDirect vs DelegatedjQuery on()Stack Overflow