Take you to understand DOM event flow

Time:2021-7-24

When doing front-end development, we often need to do various interactions, such as mouse click / double click / slide events, keyboard events, etc. These are DOM events. First, let’s look at a concept called DOM event flow.

DOM event flow

Event flow: the sequence in which events are triggered between the target element and the ancestor element.

Students at the front-end of learning will certainly not be unfamiliar with the event flow, that is, bubbling and capturing? Yes, events will not only act on bound elements, but will have a flow direction. If DOM elements in the flow direction bind events, they will respond. In the early days, Microsoft and Netscape realized the opposite event flow. Netscape advocated capture mode and Microsoft advocated bubble mode.

  • Capture: events propagate from the top level down to the target element.
  • Bubble: the event is received by the first triggered element, and then propagates upward step by step.

Finally, the W3C adopted a compromise approach, stipulating that capture first and then bubble, so as to calm the war. Such an event is divided into three stages (yes, not just capture and bubbling):

  • Capture phase: the event is passed from the topmost element window to the parent element of the target element.
  • Target stage: the event reaches the target element. If the event specifies not to bubble, it will be aborted here.
  • bubbling phase : events are passed level by level from the parent element of the target element to the topmost element window.

That is, as shown in the figure below, there is only a general concept here, and these stages will be introduced in detail later:

Take you to understand DOM event flow

Now that we have a general understanding of event flow, let’s take a look at the DOM level.

DOM level

What is the DOM level? In fact, it is some specifications of DOM in different periods, such as Es5, ES6, ES7 in JavaScript, which means to constantly add some new things to it. DOM levels include dom0, dom1, dom2 and dom3. Dom1 has nothing to do with events and will not be introduced.

DOM level 0 events

Why start with 0? Because this is not the W3C specification. At the beginning, there was no specification, but each browser did so by convention, so it became a de facto “specification”.

So what is DOM 0 level event handling? Dom0 level event is to assign a function to an event processing attribute, such as:

< button id = "BTN" type = "button" > Click me < / button >
<script>
     var btn = document.getElementById('btn');
     btn.onclick = function() {
         alert('Hello World');
     }
 // btn.onclick = null;  Unbinding event 
</script>

In the above code, we define an ID for the button, obtain the button with this ID through JS, and assign a function to an event processing attribute onclick. This method is the embodiment of dom0 level event processing. We can unbind the event by assigning null to the event processing property.

The disadvantage of dom0 level event handlers is that they are a handlerCannot bind multiple handler functions at the same timeFor example, I also want to add another function to the button click event.

DOM Level 2 events

Based on dom0 level events, dom2 level events make up for the disadvantage that multiple handler functions cannot be bound at the same time, and allow multiple handler functions (addeventlistener) to be added to a DOM element. After running the following code and clicking the button, we can find that both events will be triggered:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    < button id = "BTN" type = "button" > Click me < / button >
    <script>
      var btn = document.getElementById('btn');
      function showFn1() {
        alert('Hello1');
      }
      function showFn2() {
        alert('Hello2');
      }
      btn.addEventListener('click', showFn1, false);
      btn.addEventListener('click', showFn2, false);
    </script>
  </body>
</html>

DOM Level 2 events defineaddEventListenerandremoveEventListenerTwo methods are used to bind and unbind events respectively. The method contains three parameters: the name of the bound event processing attribute (note that it does not include on), the processing function, and whether to execute in the capture phase.

Dom3 level event

Dom3 level events add more event types to dom2 level events. All types are as follows:

  1. UI events are triggered when the user interacts with elements on the page, such as load and scroll
  2. Focus event, triggered when an element gains or loses focus, such as blur and focus
  3. Mouse events are triggered when the user performs operations on the page through the mouse, such as dbclick and mouseup
  4. Wheel event, which is triggered when a mouse wheel or similar device is used, such as mousewheel
  5. Text event, triggered when text is entered in a document, such as textinput
  6. Keyboard events are triggered when the user performs operations on the page through the keyboard, such as Keydown and keypress
  7. Synthesis event, triggered when characters are input for IME (input method editor), such as composition start
  8. When the underlying structure changes, such as modified DOM

At the same time, dom3 level events also allow users to customize some events.

Detailed event flow

Take you to understand DOM event flow

Event Bubbling

The so-called event bubbling means that events are generated from the beginning like bubbles, layer by layer. For example, tag a in the above figure is the event target. Clicking tag a will also trigger click events on P and Li, layer by layer up to the outermost HTML or document. Here is a code example:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <p id="parent" style="background-color: red;padding: 20px">
    <a id="child" style="background-color: blue;"> Event bubbling</a>
  </p>
  <script>
    var parent = document.getElementById('parent');
    var child = document.getElementById('child');
    child.addEventListener('click', function () {
      Alert ('I am target a ');
    }, false);
    parent.addEventListener('click', function () {
      Alert ('event bubbling to p ');
    }, false);
  </script>
</body>

</html>

After the above code runs, we click the a tab, and the prompt [I am target a] will pop up first, and then the prompt [event bubbling to P] will pop up, which indicates that the event bubbled from the inside to the outside.

Event capture

In contrast to event bubbling, event capture is performed from top to bottom. We just need toaddEventListenerJust change the third parameter of to true. Similarly to the above example, we add a binding in the capture phase on the P tag. The code is as follows:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <p id="parent" style="background-color: red;padding: 20px">
    <a id="child" style="background-color: blue;"> Event bubbling</a>
  </p>
  <script>
    var parent = document.getElementById('parent');
    var child = document.getElementById('child');
    //Add events for this capture phase
    parent.addEventListener('click', function () {
      Alert ('event captured to p ');
    }, true);
    child.addEventListener('click', function () {
      Alert ('I am target a ');
    }, false);
    parent.addEventListener('click', function () {
      Alert ('event bubbling to p ');
    }, false);
  </script>
</body>

</html>

After the above code runs, we click the a tag, and the prompt sequence is: [event capture to P] – [I am target a] – [event bubble to P]. It can be seen that the event is indeed as shown in the figure above. It is captured first and then bubbled.

Termination event propagation

No matter in the capture phase or bubble phase, we don’t want the event to be delivered again, so how can we stop it? Then we can useEventObject stopPropagation method. andEventHow to get it? In fact, each event response function has a parameter, which is the event object.

The same is the above example. When clicking the a tag, if we block the transmission of events in the capture phase of the P tag, the subsequent events will not be executed. The code example is as follows:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <p id="parent" style="background-color: red;padding: 20px">
    <a id="child" style="background-color: blue;"> Event bubbling</a>
  </p>
  <script>
    var parent = document.getElementById('parent');
    var child = document.getElementById('child');
    parent.addEventListener('click', function (e) {
      Alert ('event captured to p ');
      //Stop propagation, "I am target a" and "event bubble to P" are not executed
      e.stopPropagation();
    }, true);
    child.addEventListener('click', function () {
      Alert ('I am target a ');
      //Prevent propagation, "event bubbling to P" is not executed
      // e.stopPropagation();
    }, false);
    parent.addEventListener('click', function () {
      Alert ('event bubbling to p ');
    }, false);
  </script>
</body>

</html>

Run and click the a tab, we can see the effect like annotation. As long as you understand the diagram of event flow and the three stages of capture / target / bubble, it is easy to understandstopPropagationPrevent these phenomena caused by event flow. What needs to be noted here isstopPropagationThis function is to prevent event propagation (as can be understood from the word), not just to prevent bubbles, which is not explained clearly in other articles.

doubt ❓

At what stage is onclick executed?

Here we are aiming atNon target stage, to modify the above example, we add an onclick event to the id = parent node, that is, the P tag.

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <p id="parent" style="background-color: red;padding: 20px">
    <a id="child" style="background-color: blue;"> Event bubbling</a>
  </p>
  <script>
    var parent = document.getElementById('parent');
    var child = document.getElementById('child');
    parent.addEventListener('click', function (e) {
      Alert ('event captured to p ');
    }, true);
    child.addEventListener('click', function () {
      Alert ('I am target a ');
    }, false);
    parent.addEventListener('click', function () {
      Alert ('event bubbling to p ');
    }, false);
    parent.onclick = function (e) {
      Alert ('p label onclick ');
    }
  </script>
</body>

</html>

We can see that there will be such an order:

[event capture to P] – [I am target a] – [event bubble to P] – [P tag onclick]

From the above results, we can draw a conclusion:Onclick is executed in the bubbling phase!!!

Then another problem comes. Since we bind two click functions in the bubbling phase of the P tag, one is added through addeventlistener (dom2 level), and the other is directly assigned to the onclick attribute (dom0 level), which of these two functions will be executed first? The direct conclusion is related to the order of binding, that is to sayWhoever writes first executes first。 Similarly to the above example, we need to adjust the order of the two functions bound to the P tag:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <p id="parent" style="background-color: red;padding: 20px">
    <a id="child" style="background-color: blue;"> Event bubbling</a>
  </p>
  <script>
    var parent = document.getElementById('parent');
    var child = document.getElementById('child');
    parent.addEventListener('click', function (e) {
      Alert ('event captured to p ');
    }, true);
    child.addEventListener('click', function () {
      Alert ('I am target a ');
    }, false);
    parent.onclick = function (e) {
      Alert ('p label onclick ');
    }
    parent.addEventListener('click', function () {
      Alert ('event bubbling to p ');
    }, false);
  </script>
</body>

</html>

We can see that it will be in this order:

After adjustment: [event capture to P] – [I am target a] – [P tag onclick] – [event bubble to P]

Before adjustment: [event capture to P] – [I am target a] – [event bubble to P] – [P tag onclick]

It can be seen that it confirms our previous conclusion.

What about the goal stage? That is, the a tag binds the onclick event and the click event through the addeventlistener. What order will it be executed at this time? Because this time is in the target stage, the execution sequence is the same as above,Bind first, execute first

To sum up, bind first and execute first. Onclick is executed in the bubbling phase.

Recommended Today

VBS obtains the operating system and its version number

VBS obtains the operating system and its version number ? 1 2 3 4 5 6 7 8 9 10 11 12 ‘************************************** ‘*by r05e ‘* operating system and its version number ‘************************************** strComputer = “.” Set objWMIService = GetObject(“winmgmts:” _  & “{impersonationLevel=impersonate}!\\” & strComputer & “\root\cimv2”) Set colOperatingSystems = objWMIService.ExecQuery _  (“Select * from […]