1. What is it#
Event delegation, in simple terms, is delegating the function of responding to an event (click
, keydown
, etc.) of an element to another element.
As mentioned earlier, the event flow goes through three stages: capturing phase -> target phase -> bubbling phase, and event delegation is completed during the bubbling phase.
Event delegation delegates the event of one or a group of elements to its parent or outer element. The actual event binding is done on the outer element, not the target element.
When the event is triggered on the target element, it will trigger the bound event on its outer element through event bubbling mechanism, and then execute the function on the outer element.
Here's an example:
For example, when multiple packages arrive at a dormitory, a clumsy method is for each person to pick up their own package.
A better method is to delegate this task to the dormitory leader, who will collect all the packages and then distribute them to each student according to the recipient.
In this case, picking up the package is an event, each student refers to the DOM
element that needs to respond to the event, and the dormitory leader who goes out to collect the packages is the delegated element.
So the actual event binding is done on this element, and the process of distributing the packages according to the recipients during event execution is to determine which one or several should match the delegated elements.
2. Application scenarios#
If we have a list with a large number of list items, and we need to respond to an event when clicking on a list item.
<ul id="list">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
......
<li>item n</li>
</ul>
If we bind a function to each list item one by one, it will consume a lot of memory.
// Get the target elements
const lis = document.getElementsByTagName("li")
// Loop through and bind the event
for (let i = 0; i < lis.length; i++) {
lis[i].onclick = function(e){
console.log(e.target.innerHTML)
}
}
At this time, event delegation can be used. Bind the click event to the parent element ul
, and then match the target element when executing the event.
// Bind the event to the parent element
document.getElementById('list').addEventListener('click', function (e) {
// Compatibility handling
var event = e || window.event;
var target = event.target || event.srcElement;
// Check if it matches the target element
if (target.nodeName.toLocaleLowerCase === 'li') {
console.log('the content is: ', target.innerHTML);
}
});
Another scenario is when there are not many list items as mentioned above, and we have bound events to each list item.
But if the user can dynamically add or remove list item elements at any time, then each time the change occurs, we need to rebind the event to the newly added elements and unbind the event from the elements to be removed.
If event delegation is used, there is no such trouble, because the event is bound to the parent element, and it is not related to the addition or removal of the target elements. Matching the target element is done during the actual execution of the event function.
Here's an example:
In the following HTML structure, clicking on the input
can dynamically add elements.
<input type="button" name="" id="btn" value="Add" />
<ul id="ul1">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
<li>item 4</li>
</ul>
Using event delegation
const oBtn = document.getElementById("btn");
const oUl = document.getElementById("ul1");
const num = 4;
// Event delegation, the added child elements also have events
oUl.onclick = function (ev) {
ev = ev || window.event;
const target = ev.target || ev.srcElement;
if (target.nodeName.toLowerCase() == 'li') {
console.log('the content is: ', target.innerHTML);
}
};
// Add new nodes
oBtn.onclick = function () {
num++;
const oLi = document.createElement('li');
oLi.innerHTML = `item ${num}`;
oUl.appendChild(oLi);
};
As you can see, using event delegation can reduce a lot of repetitive work in the case of dynamically binding events.
3. Summary#
Events suitable for event delegation are: click
, mousedown
, mouseup
, keydown
, keyup
, keypress
.
From the above application scenarios, we can see two major advantages of using event delegation:
- Reduce the memory required for the entire page and improve overall performance.
- Dynamic binding reduces repetitive work.
However, there are limitations to using event delegation:
- Events like
focus
andblur
do not have event bubbling mechanism, so they cannot be delegated. - Events like
mousemove
andmouseout
have event bubbling, but they can only be continuously positioned, which consumes a lot of performance, so they are not suitable for event delegation.
If all events are delegated, there may be event misjudgment, that is, events that should not be triggered are bound to events.