“This is the 8th day of my participation in the First Challenge 2022. For details: First Challenge 2022”

The event flow model in JavaScrip is divided into three stages: event capture, event target and event bubbling.

Phase 1: capture phase, conduction from the Window object to the target node Phase 2: target phase, event is triggered on the target node phase 3: bubble phase, return window object from the target node

<html>
    <body>
        <div class="parent">
              <div class="target">
              </div>
        </div>
    </body>
</html>
Copy the code

  • Event CapturingFrom the outside in, from the parent of the DOM tree to the child,document -> html -> body -> parent -> target
  • Event bubblingFrom the inside out, from the child of the DOM tree to the parent,target -> parent -> body -> html -> document
  • Event TargetIt refers to the first stage of the event bubbling, that is, bubblingtargetEvents are emitted, so the target phase is also treated as part of the event bubble

Event bubbling VS event capture

Event bubbling and event capture were proposed by Microsoft and Netscape respectively, but the W3C settled the debate by combining the two to create a unified standard — capture first, bubble later.

Binding of events

El.onclick =function(){};

Dom0-level events override each other (i.e., bind el to onclick and only one will be valid), so it is not recommended at this time

DOM2 event binding standard browser: el.adDeventListener (‘click’,function(){},false)

IE6-8: el.attachEvent('onclick',function(){})

addEventListener

In JavaScript, the DOM’s addEventListener method is used to add event handles to the specified element. Syntax: element.addEventListener(event, function, useCapture)

element The target element
event Event name, such as “click”
function The function that is executed when an event is raised
useCapture Boolean value, true – Event handle incapturePhase execution; False – The default event handle is inThe bubblingStage to perform

Not all events can bubble or capture. For example, blur, Focus, load, and resize events do not support bubble or capture. See MDN for details.

Event capture

Let’s first guess the code below. When we click on a div with class target, what is the output order

const parent = document.querySelector('.parent')
const target = document.querySelector('.target')
const html = document.querySelector('html')

document.addEventListener('click'.() = >{console.log('the document capture')}, true)
html.addEventListener('click'.() = >{console.log('HTML capture')}, true)
document.body.addEventListener('click'.() = >{console.log('body capture')}, true)
parent.addEventListener('click'.() = >{console.log('the parent trap')}, true)
target.addEventListener('click'.() = >{console.log('target capture')}, true)
Copy the code

Document capture -> HTML capture -> body capture -> parent capture -> target capture will be output according to the rules of capture event flow model from the outside in

The event bubbling

Let’s change all of the above code from true to false and see what happens.

const parent = document.querySelector('.parent')
const target = document.querySelector('.target')
const html = document.querySelector('html')

document.addEventListener('click'.() = >{console.log('document' bubble.)}, false)
html.addEventListener('click'.() = >{console.log('HTML' bubble.)}, false)
document.body.addEventListener('click'.() = >{console.log('body bubbling')}, false)
parent.addEventListener('click'.() = >{console.log('parent' bubble.)}, false)
target.addEventListener('click'.() = >{console.log('target' bubble.)}, false)
Copy the code

According to the rules of the bubble event flow model from the outside in, the output target bubble -> parent bubble -> body bubble -> HTML bubble -> Document bubble

Event bubbling & event capture exists simultaneously

What if two event flow models exist at the same time?

const parent = document.querySelector('.parent')
const target = document.querySelector('.target')
const html = document.querySelector('html')

document.addEventListener('click'.() = >{console.log('the document capture')}, true)
document.addEventListener('click'.() = >{console.log('document' bubble.)}, false)
html.addEventListener('click'.() = >{console.log('HTML capture')}, true)
html.addEventListener('click'.() = >{console.log('HTML' bubble.)}, false)
document.body.addEventListener('click'.() = >{console.log('body capture')}, true)
document.body.addEventListener('click'.() = >{console.log('body bubbling')}, false)
parent.addEventListener('click'.() = >{console.log('the parent trap')}, true)
parent.addEventListener('click'.() = >{console.log('parent' bubble.)}, false)
target.addEventListener('click'.() = >{console.log('target capture')}, true)
target.addEventListener('click'.() = >{console.log('target' bubble.)}, false)
target.addEventListener('click'.() = >{console.log('target capture 1')}, true)
target.addEventListener('click'.() = >{console.log('target bubbling 1')}, false)
Copy the code

Principle:

  • From the outside in, the capture proceeds, and the capture event is executed immediately
  • Non-target nodes, catch first and bubble later
  • Target nodes, executed in code written order (whether bubbling or capturing)

So it prints: Document capture -> HTML capture -> body capture -> parent capture -> target capture -> target capture 1 -> target bubble 1 -> parent bubble -> Body bubble -> HTML bubble -> document bubble

The event object

The first argument to an event handler is the current event object, which is usually received as either event or e.

event.target

We can use event.target to get the target of the current event. For example, in the example above, if target is clicked, then event.target is target. If parent is clicked then event.target is parent.

It is fixed that at any stage of an event, event.target is the target object of the current event.

const target = document.querySelector('.target')

// e.target depends on who you click on
document.addEventListener('click'.function (e){
    console.log(e.target);// target
}, true)
document.addEventListener('click'.function (e){
    console.log(e.target);// target
}, false)
target.addEventListener('click'.function (e){
    console.log(e.target);// target
})
Copy the code

And this event. The currentTarget

If you do not use the arrow function or a function that is already bound to this as the event handler, the event. CurrentTarget will always refer to the event’s current handler.

Event bubble and capture phase, who does this point to in the handler function this is a common interview question.

const parent = document.querySelector('.parent')
const target = document.querySelector('.target')
const html = document.querySelector('html')

document.addEventListener('click'.function (e){
    console.log(e.target);// target
    console.log(e.currentTarget);// document
    console.log(this);// document
}, true)
parent.addEventListener('click'.(e) = > {
    console.log(e.target);// target
    console.log(e.currentTarget);// parent
    console.log(this);// window
}, false)
target.addEventListener('click'.function (e){
    console.log(e.target);// target
    console.log(e.currentTarget);// target
    console.log(this);// target
})
Copy the code

How do I prevent event capture/bubbling

If we want the target event to fire without triggering the corresponding event of the parent element (that is, closing the bubble process), we should prevent this behavior by calling the Event stopPropagation method or stopImmediatePropagation method.

1. StopImmediatePropagation Method: The stopImmediatePropagation method acts on the current node and all subsequent nodes in the event chain. Its purpose is to stop the running of the event handlers of the current node and all subsequent nodes after the execution of the current event handler

2. StopPropagation method: The stopPropagation method is applied to subsequent nodes to stop the execution of event handlers of all subsequent nodes after the execution of all event handlers bound to the current element

The difference between stopPropagation and stopImmediatePropagation is that stopPropagation does not prevent the execution of other handlers on the current node, but it does prevent events on other subsequent nodes in the event flow model. StopImmediatePropagation prevents other handlers of the current node from executing based on the events of subsequent nodes in the event flow model.

const parent = document.querySelector('.parent')
const target = document.querySelector('.target')

parent.addEventListener('click'.(e) = > {
    e.stopPropagation()
    console.log('the parent capture 1');
}, true)
parent.addEventListener('click'.(e) = > {console.log('the parent capture 2'); },true)
parent.addEventListener('click'.(e) = > {console.log('the parent 1' bubble.)})
parent.addEventListener('click'.(e) = > {console.log('the parent 2' bubble.)})
target.addEventListener('click'.(e) = > {console.log('target' bubble.); })Copy the code

Print parent capture 1 -> parent capture 2

If you use stopImmediatePropagation:

const parent = document.querySelector('.parent')
const target = document.querySelector('.target')

parent.addEventListener('click'.(e) = > {
    e.stopImmediatePropagation()
    console.log('the parent capture 1');
}, true)
parent.addEventListener('click'.(e) = > {console.log('the parent capture 2'); },true)
parent.addEventListener('click'.(e) = > {console.log('the parent 1' bubble.)})
parent.addEventListener('click'.(e) = > {console.log('the parent 2' bubble.)})
target.addEventListener('click'.(e) = > {console.log('target' bubble.); })Copy the code

Only parent captures 1

Blocking default behavior

event.preventDefalut()

Certain events on certain nodes in js trigger some default behavior, For example, the click event of a tag triggers a jump, the Submit event of a form triggers the submission action, and the Click event of a button of type=submit triggers the Submit event of the outer form form, etc.

If we don’t want to trigger these behaviors, the event.preventdefalut () method is called to prevent them

<a href="https://baidu.com" id="baiduLink">https://baidu.com</a>

<script>
const baiduLink = document.querySelector('#baiduLink')

baiduLink.addEventListener('click'.(e) = > {
    e.preventDefault()
})
</script>
Copy the code

Clicking on the A TAB now does not jump

The above is to introduce JS event binding, event flow model, I hope to help you.