As a front-end code farmer , In the development process, we encounter the functions that need to interact with users or need to be triggered by users , It's always about event handling .
Today, let's talk about the browser DOM Event delivery mechanism .
DOM event
In browser Javascript Engine parsing HTML、SVG when , Will analyze the content into one by one DOM (Document Object Model), When users and DOM When there is interaction , It is through DOM Event listeners registered on , To trigger an event .
For example, common onClick
、onTouchStart
, Input box onInput
、onChange
、onBlur
etc. , Are common event types .
Event monitoring
For example, we used to be most familiar with jQuery, We will register event listeners in this way :
$('#id').on('click', function(){ ... })
but jQuery Has become a thing of the past ; In the modern framework ,Vue Some syntax sugar is provided for registering event listeners , Make it easy for you to write :
<button @click="clickHandler">click me!</button>
React Besides grammar sugar , The bottom will also DOM The event is encapsulated in another layer , And help you all agent To document
On , Very good performance :
<button onClick={clickHandler}>click me!</button>
Of course, no matter what the framework is , The bottom is the same as passing through Javascript To operate :
document.querySelector('#id').addEventListener('click', clickHandler)
Event agent
It was said that React Will help you to delegate the incident to document On , What does that mean ?
Look at this A simple little example , Click the button to add li
when , Event monitoring will be registered as well :
<!--HTML-->
<button id="push">push</button>
<button id="pop">pop</button>
<ul id="list"></ul>
/*JavaScript*/
(function() {
document.querySelector('#push').addEventListener('click', pushHandler)
document.querySelector('#pop').addEventListener('click', popHandler)
const list = document.querySelector('#list')
function pushHandler() {
list.appendChild(getNewElem(list.childNodes.length))
}
function popHandler() {
document.querySelectorAll('#list>li')[list.childNodes.length - 1].remove()
}
function getNewElem(text) {
const elem = document.createElement('li')
elem.innerText = text
elem.addEventListener('click', eventHandler)
return elem
}
function eventHandler(e) {
alert(e.target.innerText)
}
})()
It's intuitive , But the disadvantages are obvious ; Every new element , Will create an event listener , As the number increases , The memory consumption will also be considerable :
function pushHandler() {
list.appendChild(getNewElem(list.childNodes.length))
}function getNewElem(text) {
const elem = document.createElement('li')
elem.innerText = text
elem.addEventListener('click', () => alert(text))
return elem
}
If you register event listeners in the outer layer of ul
, And determine who is triggered when the event is triggered :
function listClickHandler(e){
if (e.target.tagName === 'LI') alert(e.target.innerText)
}
Through the event agent , No matter how much content , There will be only one group for event monitoring , Efficiency has been greatly improved .
Remove event monitoring
It's convenient to register event listeners , But when you're sure you won't use the monitor again , Remember to pass removeEventListener
Remove event monitoring . If you leave a useless event listener , It will cause a waste of memory , Great damage to performance .
You should have noticed , In the previous simple little example, event monitoring is not removed , And every time you create a new child element , Will create new functions at the same time :
function getNewElem(text) {
const elem = document.createElement('li')
elem.innerText = text
// Create a new anonymous function here
elem.addEventListener('click', () => alert(text)) return elem
}
A better way to write it is to extract anonymous functions , And remove the event listener when removing child elements :
function popHandler() {
const elem = document.querySelectorAll('#list>li')[list.childNodes.length - 1]
elem.removeEventListener('click', eventHandler) // Remove event monitoring
elem.remove()
}function getNewElem(text) {
const elem = document.createElement('li')
elem.innerText = text
elem.addEventListener('click', eventHandler)
return elem
}function eventHandler(e) {
alert(e.target.innerText)
}
stay Vue and React In the mainstream web framework , As long as it is an event listener registered with the built-in Syntax , They are automatically removed when they are not useful , Safe to use ; If you implement event monitoring yourself , Be sure to remember to remove .
Capture and bubble
It's too far from the point , So what is capture and bubbling ?
according to W3C Defined by the Event Flow:
The event passing process in the browser is divided into three stages :
- Capture phase : from DOM The outermost layer of the tree goes in order , In the process, the capture phase event listening of individual elements is triggered .
- Target stage : Reach the event target , Trigger event monitoring according to the registration order .
- bubbling phase : From the event target to the outside in order , In the procedure, the bubbling phase event listening of individual elements is triggered .
This is the mechanism of event broker just mentioned ; In the event delivery process , The capture bubble phase must go through the outer elements , So you can register event listeners on outer elements .
in addition , When we use addEventListener
When registering event listeners , You can pass the third parameter , Specifies the stage at which this event is to be triggered :
elem.addEventListener('click', eventHandler) // Not specified , The default is bubble
elem.addEventListener('click', eventHandler, false) // Bubbling
elem.addEventListener('click', eventHandler, true) // Capture
elem.addEventListener('click', eventHandler, {
capture: true // Whether it's capture . IE、Edge No support . For other properties, please refer to MDN
})
As shown in the figure above , When one DOM Event time , It's going to be the outermost window
Start passing events in turn , All the way to our event target , Trigger event monitoring registered on target , And then into the bubbling stage, reverse transfer ; The stage triggered by the specified , We can determine the order of execution .
This article first send WeChat messages public number : Front end pioneer
Welcome to scan the two-dimensional code to pay attention to the official account. , I push you fresh front-end technical articles every day
Welcome to the rest of this column :
- In depth understanding of Shadow DOM v1
- Step by step, teach you how to use WebVR Realize virtual reality games
- 13 A modern technology that helps you improve your development efficiency CSS frame
- Quick start BootstrapVue
- JavaScript How the engine works ? From the call stack to Promise Everything you need to know
- WebSocket actual combat : stay Node and React Real time communication between
- About Git Of 20 One interview question
- In depth analysis of Node.js Of console.log
- Node.js What is it ?
- 30 Minutes Node.js Construct a API The server
- Javascript Object copy of
- The programmer 30 A month's salary before the age of 30K, Where to go
- 14 The best JavaScript Data visualization Library
- 8 To the top of the front end VS Code Extension plug-in
- Node.js Multithreading Complete Guide
- hold HTML Turn into PDF Of 4 Project and implementation