YUI recommends YUI3.
YUI 2 has been deprecated since 2011. This site acts as an archive for files and documentation.
This documentation is no longer maintained.
Event delegation is a technique whereby you use a single event handler on a parent element to listen for interactions that affect the parent's descendant elements; because events on the descendant elements will bubble up to the parent, this can be a reliable and extremely efficient mitigation strategy for reducing the number of resource-consuming event handlers you have on any given page. (You can read more about Event Delegation in this YUIBlog article.)
In the example below, mousing over an item in the list will change its
background color to yellow. Clicking an item will change its
background color to red. Because we're using event delegation, only one event
listener is needed for each type of event (click
,
mouseover
, and mouseout
), regardless of the size of
the list. To illustrate this point, click the "Add Item" button to append more
items to list. An infinite number of items can be added to the list, and still
just one click
, mouseover
, and mouseout
event handler is required to highlight the items.
Event delegation refers to the use of a single event listener on a parent object to listen for events happening on its children (or deeper descendants). Event delegation allows developers to be sparse in their application of event listeners while still reacting to events as they happen on highly specific targets. This proves to be a key strategy for maintaining high performance in event-rich web projects, where the creation of hundreds of event listeners can quickly degrade performance.
This example illustrates the use of event delegation (via the
Event Utility) on
click
, mouseover
, and mouseout
events.
The problem we will solve here involves reacting to click
,
mouseover
, and mouseout
events on list items. As
there can be many list items, we want to be frugal in applying event listeners.
At the same time, we want to know exactly which <li>
was
involved in a click
, mouseover
, and
mouseout
event.
To do this, we'll rely on DOM event bubbling — the process by which an
event progresses from its direct target up through the target's node ancestry
until it reaches the window
object. The graphic below may help to
illustrate the flow: In this case, we'll count on the fact that a click or a
mouseover on (A) the text node within an <li>
progresses to the <li>
element itself (B), then to the
<ul>
element (C), and then to the list's parent
<div>
(D) and so on up the document:
Because events flow this way, we can count on events happening to our
<li>s
bubbling up to our <div> whose ID attribute is
"container."
We'll start with some structural markup — a <div>
containing a <ul>
with 5 <li>
children.
1 | <div id="container"> |
2 | <ul id="list"> |
3 | <li id="li-1">List Item 1</li> |
4 | <li id="li-2">List Item 2</li> |
5 | <li id="li-3">List Item 3</li> |
6 | <li id="li-4">List Item 4</li> |
7 | <li id="li-5">List Item 5</li> |
8 | </ul> |
9 | </div> |
view plain | print | ? |
The Event Utility makes using event delegation easy by providing a
delegate
method that enables the use of CSS selector
syntax to define the descendants of the delegation container for which the
event listener should be called. Note: Event's delegation functionality
is packaged separately in an event-delegate module, which itself requires the
Selector Utility.
To use the delegate
method, pass the id of the element that is
the delegation container as the first argument (in this case
<div id="container">
). The second argument is the
type of event you want to delegate, and the third is the event listener. The
forth argument is a CSS selector that defines the descendant elements that must
match the target of the event in order for the listener to be called.
First we'll add the event listener used to highlight each item when it is
clicked. As we're only really interested in clicks on <li>
s,
we'll specify a CSS selector of "li" as the fourth argument to the
delegate
method. The element that matched the CSS selector
will be passed as the second argument to the event listener. The element
that is the delegation container for the listener is passed as the third
argument:
1 | (function() { |
2 | |
3 | var Dom = YAHOO.util.Dom, |
4 | Event = YAHOO.util.Event; |
5 | |
6 | var onLIClick = function (event, matchedEl, container) { |
7 | |
8 | if (Dom.hasClass(matchedEl, "selected")) { |
9 | Dom.removeClass(matchedEl, "selected"); |
10 | } |
11 | else { |
12 | Dom.addClass(matchedEl, "selected"); |
13 | } |
14 | |
15 | }; |
16 | |
17 | // Use the "delegate" method to attach a "click" event listener to the |
18 | // container (<div id="container">). The listener will only be called if the |
19 | // target of the click event matches the element specified via the CSS |
20 | // selector passed as the fourth argument to the delegate method. |
21 | |
22 | Event.delegate("container", "click", onLIClick, "li"); |
23 | |
24 | })(); |
view plain | print | ? |
The same technique works for the mouseover
and
mouseout
events as well.
1 | (function() { |
2 | |
3 | var Dom = YAHOO.util.Dom, |
4 | Event = YAHOO.util.Event; |
5 | |
6 | var onLIMouseOver = function (event, matchedEl, container) { |
7 | |
8 | Dom.addClass(matchedEl, "hover"); |
9 | }; |
10 | |
11 | var onLIMouseOut = function (event, matchedEl, container) { |
12 | |
13 | Dom.removeClass(matchedEl, "hover"); |
14 | |
15 | }; |
16 | |
17 | |
18 | // Use the "delegate" method to attach a mouseover and mouseout event listener |
19 | // to the container (<div id="container">). The listener will only be called |
20 | // if the target of the click event matches the element specified via the CSS |
21 | // selector passed as the fourth argument to the delegate method. |
22 | |
23 | Event.delegate("container", "mouseover", onLIMouseOver, "li"); |
24 | Event.delegate("container", "mouseout", onLIMouseOut, "li"); |
25 | |
26 | })(); |
view plain | print | ? |
In this example, we've used three event listeners with their associated memory
and performance load to serve as delegates for the same three events on each
item in the list. Instead of 3 event listeners per item, we now have three
on the container. And
the code works regardless of the number of li
's added to the list
— if the list was 100 items long, we'd be saving ourselves 297 event
listeners, which is enough to make a noticable difference in how your page
responds. In a complicated page context, it's easy to see how this technique
can dramatically reduce the number of event listeners required and thereby
improve the performance of your application.
Note: Logging and debugging is currently turned off for this example.
All YUI 2.x users should review the YUI 2.8.2 security bulletin, which discusses a vulnerability present in YUI 2.4.0-2.8.1.
Copyright © 2013 Yahoo! Inc. All rights reserved.