event
Event bubbling and event capture were proposed by Microsoft and Netscape respectively. These two concepts are to solve the problem of event flow (event sequence) in the page. Before the event flow, that is, the sequence of events, let's take a look at the DOM tree
1. DOM tree
How is the DOM tree formed? The code we write in VScode will parse the HTML document into a DOM tree structure through a special HTML parser. The root node of the DOM tree is the document object. In the process of parsing, the HTML parser finds the imported file in, so it requests the file from the server. Note that the link file will continue to parse the HTML downward in the process of requesting and downloading the file. When the imported file is downloaded, it will notify the browser to parse it back; Is non blocking. The script file will wait for the file to be downloaded and executed immediately. After execution, it will be parsed downward, which is blocked. So put the css file at the top and the script tag at the bottom of the body.
For example:
<!DOCTYPE html> <html lang="en"> <head> <title>Document</title> </head> <body> <a href="#"> my link</a> <h1>My title</h1> </body> </html>
Then the DOM tree parsed by the HTML parser is:
2. Stream DOM events
DOM event flow includes event capture stage, target stage and bubble stage.
The event capture stage is to look down from the root node of the DOM tree. The target stage is to find the clicked element. The bubbling stage is to find the element and then layer by layer online to tell the browser that the clicked element has been found.
For example:
3. Event flow verification
3.1 capture phase
If the son is clicked, according to the capture principle of event flow, if the grandfather on the outermost layer of the package is bound with a click event, the event will also be executed. Therefore, the click event of the father will be executed first, then the click event of the father, and then the click event of the son will be executed.
<div id="grandpa"> father <div id="father"> dad <div id="son"> Son </div> </div> </div> <script> let grandpa = document.getElementById('grandpa'); let father = document.getElementById('father'); let son = document.getElementById('son'); // true is to enable event flow capture grandpa.addEventListener('click', function () { console.log('I'm Grandpa'); }, true) father.addEventListener('click', function () { console.log('I'm daddy'); }, true) son.addEventListener('click', function () { console.log('It's my son'); }, true) </script>
3.2 bubbling stage
If the son is clicked, there is a bubbling stage according to the event flow. As long as the father wrapping the son binds the click event, the event above the father will also be executed. So was grandpa's case.
<div id="grandpa"> father <div id="father"> dad <div id="son"> Son </div> </div> </div> <script> let grandpa = document.getElementById('grandpa'); let father = document.getElementById('father'); let son = document.getElementById('son'); grandpa.addEventListener('click', function () { console.log('I'm Grandpa'); }) father.addEventListener('click', function () { console.log('I'm daddy'); }) son.addEventListener('click', function () { console.log('It's my son'); }) </script>
3.3 preventing bubbling
There is a time when we don't want to wrap our son's father to trigger the event. At this time, we need to stop the bubble event through event The stoppropagation() statement blocks bubbling events
<div id="grandpa"> father <div id="father"> dad <div id="son"> Son </div> </div> </div> <script> let grandpa = document.getElementById('grandpa'); let father = document.getElementById('father'); let son = document.getElementById('son'); grandpa.addEventListener('click', function () { console.log('I'm Grandpa'); }) father.addEventListener('click', function () { console.log('I'm daddy'); }) son.addEventListener('click', function () { console.log('It's my son'); // Stop bubbling event.stopPropagation(); }) </script>
3.4 event. The difference between target and this in event handlers
- event.target is the element that is actually clicked
- this is the element that binds the event
<ul> <li>0</li> <li>1</li> <li>2</li> <li>3</li> </ul> <script> // 1. Get ul element var ul = document.querySelector('ul'); // 2. Add click event to ul ul.addEventListener('click',function(){ // 3. Print the content of the currently clicked element in the event handler console.log(event.target.innerHTML); console.log(this); }) </script>
3.5 event delegation
Event delegation uses the bubbling principle in the event flow to delegate the event to the parent element and use event Target gets the clicked element and executes the callback function when it gets the clicked element
<!-- 1.Create a ul,There are 10 inside li Element, click li Print when element'Click li' --> <ul> <li>0</li> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> <li>6</li> <li>7</li> <li>8</li> <li>9</li> </ul> <script> var ul = document.querySelector('ul'); //The event is bound to the parent element ul through event Target gets the clicked element ul.addEventListener('click',function(){ console.log(event.target.innerHTML); }) </script>
3.6 problems of mobile terminal click events
Mobile terminal click event delay 300ms
The mobile browser will have some default behaviors, such as double-click zoom and double-click scroll. These behaviors, especially double-click zoom, are mainly designed for the browsing experience of desktop websites on the mobile side. When the user operates the page, the mobile browser will give priority to judge whether the user wants to trigger the default behavior User in iOS Safari Click a link inside. Since the user can double-click zoom or double-click scroll, When the user clicks the screen once, the browser cannot immediately determine whether the user really wants to open the link or double-click. So, iOS Safari Just wait 300 milliseconds to determine whether the user clicked on the screen again. Whereas iPhone Your success, Other mobile browsers have been copied iPhone Safari Most browser conventions, including double-click zoom, Almost all mobile browsers now have this function
Mobile terminal click event penetration
Cause: the sequence of events is touchstart > touchend > click
There are two elements A and B on the page. Element B is above element A. We registered A callback function on the touchstart event of element B, which is used to hide element B. We found that when we click on element B, element B is hidden, and then element A triggers the click event
resolvent
Use fastclick JS can be solved with fastclick
fastclick principle:
When the touchend event is detected, it will immediately start to simulate a click event through the DOM custom event,
And stop the real click event of the browser after 300ms
Usage: in main Install, import and transform global click events in JS
<div style='width: 400px;height: 400px;background-color: blue;position: relative;'> <div class='inner' style='width: 200px;height: 200px;background-color: blueviolet;'></div> <div class='inner' style='width: 200px;height: 200px;background-color: yellow;position: absolute;left: 50px;top: 50px;'></div> </div> //Introduce fastclick js <script src="./fastclick.js"></script> <script> var wrap = document.querySelector('div'); var inner1 = document.querySelectorAll('.inner')[0]; var inner2 = document.querySelectorAll('.inner')[1]; //Solve click penetration and delay of 300ms if ('addEventListener' in document) { document.addEventListener('DOMContentLoaded', function () { FastClick.attach(document.body); }, false); } inner2.addEventListener('touchend', function () { wrap.removeChild(this); }) inner1.addEventListener('click', function () { console.log(1); }) </script>