Detailed explanation of JavaScript event flow

DOM event flow

To understand the event flow, we must first understand three points:

  • Elements are not independent, they are connected in series
  • After a single element triggers an event, it will affect other elements
  • Mode of event flow: event capture (proposed by Netscape) and event bubbling (proposed by IE)

Let's take the above figure as an example. Suppose you bind a click event to a Div. when you click a div, other elements will also be involved, which will cause the effect of pulling one hair and affecting the whole body.

There are two ways of event flow: event bubbling and event capture

Event Bubbling


Event bubbling stage: trigger the target event immediately after clicking div, and then bubble up one layer at a time

Event capture


Event capture stage: after clicking div, the event of div will not be triggered immediately, but will be captured layer by layer, and the event will not be triggered until it reaches Div.

In fact, these two stages may be encountered in future project development, because different event binding methods create different event stages (bubble / capture)

Scenario 1: bind events directly in HTML

<body onclick="console.log('I am body')">
    <button onclick="console.log('I am button')">
        <span onclick="console.log('I am span')">Happy button</span>
    </button>
</body>

effect:

As can be seen from the above figure, when we click the span tab, the events on the upper button and the events on the body will be executed in bubble order

Scenario 2: [domnode] Onclick() mode - DOM0 level

html:

<body>
    <button>
        <span>Happy button</span>
    </button>
</body>

javascript:

var body = document.getElementsByTagName('body')[0];
var button = document.getElementsByTagName('button')[0];
var span = document.getElementsByTagName('span')[0];

body.onclick = function() {console.log('I am body')};
button.onclick = function() {console.log('I am button')};
span.onclick = function() {console.log('I am span')};

effect:

We found that the way DOM 0 binds events is still bubbling

Scenario 3: [domnode] Addeventlistener() method - DOM2 level

Addevenlistener (event name, callback after event triggering, Boolean value)

False (default): indicates that the event handler is called during the bubbling phase
true: indicates that the event handler is called in the capture phase

html:

<body>
    <button>
        <span>Happy button</span>
    </button>
</body>

javascript:

var body = document.getElementsByTagName('body')[0];
var button = document.getElementsByTagName('button')[0];
var span = document.getElementsByTagName('span')[0];

function theName() {console.log('I am' + this.nodeName)};

body.addEventListener('click',theName,false);
button.addEventListener('click',theName,false);
span.addEventListener('click',theName,false);

effect:

We can see that when the third parameter of addEventListener is false (the default is false without writing), the event flow is bubbling.

When we change the third parameter to true:

......
body.addEventListener('click',theName,true);
button.addEventListener('click',theName,true);
span.addEventListener('click',theName,true);


We found that the execution order is body - > button - > span, which is the event capture stage.

DOM Level 2 regulations:

  • The event flow includes three stages (1. Capture stage, 2. Target stage, 3. Bubbling stage)
  • The execution sequence should follow: capture phase - > target phase - > bubbling phase

That is, when you click the target element, the trigger event will not be executed immediately, but the event capture phase - > and then the target phase (trigger event) - > Event bubble phase

Let's take a look at a classic interview question: the output order when we click on baby?

html:

<body>
    <div class="grandma">grandma grandma
        <div class="mother">mother mom
            <div class="daughter">daughter
                <div class="baby">baby baby</div>
            </div>
        </div>
    </div>
</body>

javascript:

var grandma = document.getElementsByClassName('grandma')[0]
var mother = document.getElementsByClassName('mother')[0]
var daughter = document.getElementsByClassName('daughter')[0]
var baby = document.getElementsByClassName('baby')[0]

function theName() {
    console.log('I am' + this.className);
}

baby.addEventListener('click', theName, false)//Bubbling
daughter.addEventListener('click', theName, true)//capture
mother.addEventListener('click', theName, true)//capture
grandma.onclick = theName//Bubbling

result:

Question making ideas:

  1. First, divide the elements bound to the event into capture? Bubbling? We can see that daugher and mother are captured; baby and grandma are bubbling
  2. Because DOM2 stipulates to capture first and then bubble, one of daugher and mother will be printed first
  3. Because the capture is from top to bottom (dom root - > DIV), print mother first and then daught
  4. Because bubbling is from bottom to top (div - > DOM root), print baby and then print grandma

Keywords: Javascript Front-end ECMAScript Interview

Added by pbjpb on Sun, 06 Mar 2022 13:48:01 +0200