DOM event propagation mechanism

Propagation mechanism of DOM events

Classic real questions

  • Let’s talk about event delegation and the bubbling principle

Events and event streams

Events first appeared in IE3 and Netscape Navigator2 as a means of sharing the computing burden of the server.

To interact with web pages, you need to use events in JavaScript .

Every time a user interacts with a web page, such as clicking a link, pressing a button, or moving the mouse, an event is triggered. Our program can detect these events and then respond to them. Thus forming an interaction.

This can make our page more interesting, not just for browsing as before.

In the early days of dial-up Internet access, if all functions were processed on the server side, the efficiency would be very low.

So JavaScript was originally designed to solve these problems. Save round trip time to the server by allowing some functions to be handled client-side.

JavaScript uses something called an event listener to monitor whether events occur. This event listener is similar to a notification. When an event occurs, the event listener will let us know, and then the program can respond accordingly.

In this way, you can avoid having the program constantly check whether the event has occurred, and allow the program to continue doing other tasks while waiting for the event to occur.

event stream

When the browser developed to the 4th generation ( IE4 and Netscape4 ), the browser development team encountered a very interesting question: Which part of the page will have a specific event?

Imagine a set of concentric circles on a piece of paper. If you place your finger on the center of the circle, your finger points not to one circle, but to all the circles on the paper.

image-20211002174941387

Fortunately, the browser development teams of the two companies still have the same view on browser events.

If a button is clicked, they all think that the click event happened not only on the button, but even on the whole page.

But what is interesting is that the IE and Netscape development teams actually came up with almost the exact opposite concept of event flow.

IE 's event stream is an event bubbling stream, while Netscape 's event stream is an event capture stream.

event bubbling stream

IE 's event flow is called event bubbling , that is, the event is initially received by the most specific element (the node with the deepest nesting level in the document), and then propagates upwards to less specific nodes (documents).

Take the following HTML structure as an example to illustrate event bubbling. as follows:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <div></div>
    </body>
</html>

If a div element in the page is clicked , then the click event propagates upward along the DOM tree, occurs on each level of node, and propagates in the following order:

  1. div
  2. body
  3. html
  4. document

All modern browsers support event bubbling, but there are still some differences in the specific implementation.

IE9, Firefox, Chrome, and Safari bubble up the event to the window object.

We can use the following code to view the specific bubbling order of the document, as shown in the following example:

<div id="box" style="height:100px;width:300px;background-color:pink;"></div>
<button id="reset">还原</button>
// IE8 以下浏览器返回 div body html document
// 其他浏览器返回 div body html document window
reset.onclick = function () {
    
    
  history.go();
}
box.onclick = function () {
    
    
  box.innerHTML += 'div\n';
}
document.body.onclick = function () {
    
    
  box.innerHTML += 'body\n';
}
document.documentElement.onclick = function () {
    
    
  box.innerHTML += 'html\n';
}
document.onclick = function () {
    
    
  box.innerHTML += 'document\n';
}
window.onclick = function () {
    
    
  box.innerHTML += 'window\n';
}

In the above example, we have bound click events to the div and its ancestor elements. Due to the existence of event bubbling, when we click the div , the click events of all ancestor elements will also be triggered.

As shown below:

image-20211002172307085

event capture stream

Another event stream proposed by the Netscape Communicator team is called event capture ( event captruing ).

The idea of ​​event capture is that less specific nodes should receive events earlier and most specific nodes should receive events last.

The idea of ​​event capture is to capture an event before it reaches its intended destination.

Take the same HTML structure as an example to illustrate event capture, as follows:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <div></div>    
    </body>
</html>

During the event capture process, the document object first receives the click event, and then the event is propagated downward along the DOM tree until it reaches the actual target of the event, which is the div element:

  1. document
  2. html
  3. body
  4. div

Modern browsers such as IE9, Firefox, Chrome, and Safari all support event capture, but they also start capturing from the window object.

Let's demonstrate an example of an event capture flow:

<div id="box" style="height:100px;width:300px;background-color:pink;"></div>
<button id="reset">还原</button>
// IE8 以下浏览器不支持
// 其他浏览器返回 window document html body div
reset.onclick = function () {
    
    
  history.go();
}
box.addEventListener('click', function () {
    
    
  box.innerHTML += 'div\n'
}, true)
document.body.addEventListener('click', function () {
    
    
  box.innerHTML += 'body\n';
}, true);
document.documentElement.addEventListener('click', function () {
    
    
  box.innerHTML += 'html\n';
}, true);
document.addEventListener('click', function () {
    
    
  box.innerHTML += 'document\n';
}, true);
window.addEventListener('click', function () {
    
    
  box.innerHTML += 'window\n';
}, true);

In the above example, we bind the click event to the div and all its ancestor elements, use the addEventListener method to bind the event, and set the second parameter to true to use event capture to trigger the event. .

Results as shown below:

image-20211002173549252

Standard DOM event flow

The DOM standard adopts the capture + bubbling method.

Both event streams will trigger all objects in the DOM , starting with the document object and ending with the document object.

In other words, both the starting point and the ending point are document objects (many browsers can always capture + bubble to the window object)

DOM event flow diagram:

image-20211002174148423

The DOM standard stipulates that the event flow includes three stages: the event capture stage , the target stage and the event bubbling stage .

  • **Event capture phase:** The actual target div will not trigger events during the capture phase. The capture phase starts from window , then to document, html , and finally to body , which means the capture phase ends.

  • **In the target phase:** The event occurs and is processed on the div , but this event processing will be regarded as part of the bubbling phase.

  • **Bubbling phase:** The event is propagated back to the document.

event delegation

The event bubbling flow is introduced above. One of the biggest benefits of event bubbling is that it can implement event delegation.

Event delegation, also known as event proxy. In JavaScript , the number of event handlers added to a page will be directly related to the overall performance of the page. There are many reasons for this problem.

First of all, every function is an object and takes up memory. The more objects in memory, the worse the performance. Secondly, the number of DOM visits caused by having to specify all event handlers in advance will delay the interactive readiness time of the entire page.

The solution to the problem of too many event handlers is event delegation.

Event delegation uses event bubbling to manage all events of a certain type by specifying only one event handler.

For example, the click event will bubble up to the document level. That is, we can specify an onclick event handler for the entire page without having to add event handlers for each clickable element.

To give a specific example, for example, my list items now have the following content:

<ul id="color-list">
  <li>red</li>
  <li>yellow</li>
  <li>blue</li>
  <li>green</li>
  <li>black</li>
  <li>white</li>
</ul>

If we want to bind event listeners to all li elements so that some text pops up when they are clicked, we need to bind an event listener to each element.

Although the above example does not seem to be a big problem, imagine if this list has 100 elements, then we need to add 100 event listeners. This workload is still terrifying.

At this time we can use the event proxy to help us solve this problem.

Bind the event listener to the parent element ul , so that events can be added to all li elements, as follows:

var colorList = document.getElementById("color-list");
colorList.addEventListener("click",function(){
    
    
  alert("Hello");
})

Now when we click any li in the list , something will pop up, as if these li elements are the target of the click event.

And if we add a new li element to this ul later , the new li element will automatically add the same event.

However, there is also a problem at this time. Although we use the event proxy to avoid adding the same event for each li element, if the user does not click li but clicks ul , the event will also be triggered.

This is normal, because our event is bound to ul .

At this point, we can make a small judgment on the clicked node, so as to ensure that the event is only triggered when the user clicks li , as follows:

var colorList = document.getElementById("color-list");
colorList.addEventListener("click", function (event) {
    
    
  if (event.target.nodeName === 'LI') {
    
    
    alert('点击 li');
  }
})

Answers to real questions

  • Let’s talk about event delegation and the bubbling principle

Reference answer:

Event delegation, also known as event proxy. In JavaScript , the number of event handlers added to a page will be directly related to the overall performance of the page. There are many reasons for this problem.

First of all, every function is an object and takes up memory. The more objects in memory, the worse the performance. Secondly, the number of DOM visits caused by having to specify all event handlers in advance will delay the interactive readiness time of the entire page.

The solution to the problem of too many event handlers is event delegation.

Event delegation uses event bubbling to manage all events of a certain type by specifying only one event handler. For example, the click event will bubble up to the document level. That is, we can specify an onclick event handler for the entire page without having to add event handlers for each clickable element.

Event bubbling ( event bubbling ) means that the event is initially received by the most specific element (the node with the deepest nesting level in the document), and then propagates upward to less specific nodes (documents).

-EOF-

Guess you like

Origin blog.csdn.net/qq_53461589/article/details/132740098