当前位置:网站首页>Capture bubbles? Is browser a fish?

Capture bubbles? Is browser a fish?

2020-11-09 08:41:41 Crazy technology house

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 onClickonTouchStart, Input box onInputonChangeonBlur 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

DOM Event  frame

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 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 :


版权声明
本文为[Crazy technology house]所创,转载请带上原文链接,感谢