DOM event mechanism

  dom, Front end, html, javascript, Programmer

Preface

This article mainly introduces DOM Event level, DOM event model, event flow, event proxy and common applications of event objects, hoping to give you some help and inspiration!

The starting address of this article isGitHub blog, writing articles is not easy, please support and pay more attention!

I. DOM Event Level

DOM levels can be divided into four levels: DOM0, DOM1, DOM2 and DOM3. AndDOM events are divided into three levels: DOM level 0 event processing, DOM level 2 event processing and DOM level 3 event processing. There are no DOM level 1 events because there are no events related to DOM level 1.

1.DOM 0 level event

el.onclick=function(){}

//Example 1
 var btn = document.getElementById('btn');
 btn.onclick = function(){
 alert(this.innerHTML);
 }

It is not allowed to bind multiple events of the same type to the same element/tag (e.g. binding 3 click events to the btn element above). DOM0 event binding, event behavior binding methods for elements,These methods are all executed in the bubbling phase (or target phase) of the current element event behavior.

Dom level 2 events

el.addEventListener(event-name, callback, useCapture)

  • Event-name: the name of the event, which can be a standard DOM event.
  • Callback: callback function, when the event is triggered, the function will be injected with an event whose parameter is the current event object
  • UseCapture: the default is false, which means that the event handle is executed during the bubbling phase.
//Example 2
 var btn = document.getElementById('btn');
 btn.addEventListener("click", test, false);
 function test(e){
 e = e || window.event;
 alert((e.target || e.srcElement).innerHTML);
 btn.removeEventListener("click", test)
 }
 //IE9-:attachEvent () and detachEvent ().
 //ie9+/chrom/ff: addeventlistener () and removeEventListener ()

AddEventListener () and removeEventListener () are not supported in IE browsers below IE9. attachEvent () and detachEvent () are used instead. Since event capture is not supported below IE9, there is no third parameter. The first event name must be preceded by on.

Dom level 3 events

More event types have been added to DOM Level 2 events.

  • UI events that are triggered when the user interacts with elements on the page, such as load, scroll
  • Focus event, triggered when an element gains or loses focus, e.g. blur, Focus
  • Mouse event, which is triggered when the user performs operations on the page through the mouse, such as: dblclick, mouseup
  • Wheel event, triggered when using mousewheel or similar equipment, e.g. mouse wheel
  • Text event, triggered when text is entered in a document, e.g. textInput
  • Keyboard event, triggered when a user performs an operation on a page through the keyboard, e.g. keydown, keypress
  • Composite event, triggered when characters are entered for IME (Input Method Editor), e.g. compositionstart
  • Change event, triggered when the underlying DOM structure changes, e.g. DOMsubtreeModified
  • At the same time, DOM3 level events also allow users to customize some events.

Second, DOM event model and event flow

DOM event model is divided into capture and bubbling. After an event occurs, it propagation between the child element and the parent element. The spread is divided into three stages.

(1) Capture phase: the phase in which events propagate from the window object to the target node from top to bottom;

(2) target stage: the stage when the real target node is handling the event;

(3) Bubble stage: the stage in which the event propagates from the target node to the window object from bottom to top.

DOM Event Capture Process

The capture is from top to bottom. The event first goes from the window object, then to the document (object), then to the html tag (the html tag is obtained through the document.documentElement), then to the body tag (the body tag is obtained through the document.body), then goes down layer by layer according to the ordinary html structure, and finally to the target element.

The process of event bubbling is just the reverse of event capture.
Next, let’s look at an example of an incident bubbling:

//Example 3
 <div id="outer">
 <div id="inner"></div>
 </div>
 ......
 window.onclick = function() {
 console.log('window');
 };
 document.onclick = function() {
 console.log('document');
 };
 document.documentElement.onclick = function() {
 console.log('html');
 };
 document.body.onclick = function() {
 console.log('body');
 }
 outer.onclick = function(ev) {
 console.log('outer');
 };
 inner.onclick = function(ev) {
 console.log('inner');
 };

As we mentioned above, onclick’s event behavior binding methods for elements are all executed in the bubbling phase (or target phase) of the current element’s event behavior.

III. Event Agency (Event Delegation)

Since the event will propagate up to the parent node in the bubbling phase, the monitoring function of the child node can be defined on the parent node, and the monitoring function of the parent node uniformly processes the events of multiple child elements. This method is called event delegation.

1. Advantages

  • Reduce memory consumption and improve performance

Assuming there is a list with a large number of list items, we need to respond to an event when clicking on each list item.

//Example 4
 <ul id="list">
 <li>item 1</li>
 <li>item 2</li>
 <li>item 3</li>
 ......
 <li>item n</li>
 </ul>

If you bind a function to each list item one by one, it will consume a lot of memory and a lot of performance in efficiency. With the help of event proxy, we only need to bind the ul method to the parent container, so that no matter which descendant element is clicked, the click behavior of the container will be triggered according to the transmission mechanism of bubbling propagation, and then the corresponding method will be executed. According to the event source, we can know who is clicked, thus completing different things.

  • Dynamic binding event

In many cases, we need to dynamically add or delete list item elements through user operations. If events are bound to each sub-element at the beginning, when the list changes, we need to rebind the newly added elements and unbind the elements to be deleted. If we use event proxies, we will save a lot of trouble.

2. How to Realize

Next, let’s implement the event delegation of li element under parent element #list to its parent element in the above example:

//Bind Events to Parent Element
 document.getElementById('list').addEventListener('click', function (e) {
 //Compatibility Handling
 var event = e || window.event;
 var target = event.target || event.srcElement;
 //Judge whether it matches the target element
 if (target.nodeName.toLocaleLowerCase === 'li') {
 console.log('the content is: ', target.innerHTML);
 }
 });

IV. Common Applications of Event Objects

  • event. preventDefault()

If this method is called, the default event behavior will no longer trigger. What is the default event? For example, when the form clicks the submit button to jump to the page, the default page jump of label a or anchor point positioning, etc.

Most of the time we use the A tag just to use it as an ordinary button, click to realize a function, and don’t want to jump pages or anchor points.

//Method 1:
 <a href="javascript:;"  > link < /a >

You can also use JS method to prevent and bind its click event. When we click the A tag, we will first trigger the Click event and then execute our default behavior.

//Method 2:
 < a id = "test" href = "http://www.cnblogs.com" > link < /a >
 <script>
 test.onclick = function(e){
 e = e || window.event;
 return false;
 }
 </script>
//Method 3:
 < a id = "test" href = "http://www.cnblogs.com" > link < /a >
 <script>
 test.onclick = function(e){
 e = e || window.event;
 e.preventDefault();
 }
 </script>

Next, let’s look at an example: the input box can only enter up to six characters, how to implement it?

//Example 5
 <input type="text" id='tempInp'>
 <script>
 tempInp.onkeydown = function(ev) {
 ev = ev || window.event;
 Let val = this.value.trim() //trim removes the first space in the string (incompatible)
 //this.value = this.value.replace (/+|+$/g,'') compatible writing
 let len = val.length
 if (len >= 6) {
 this.value = val.substr(0, 6);
 //block default behavior to remove special keys (DELETE\BACK-SPACE\ arrow keys ...)
 let code = ev.which || ev.keyCode;
 if (!  /^(46|8|37|38|39|40)$/.test(code)) {
 ev.preventDefault()
 }
 }
 }
 </script>
  • event.stopPropagation() & event.stopImmediatePropagation()

The event.stopPropagation () method prevents the event from bubbling to the parent element and prevents any parent event handler from being executed. The above-mentioned event bubbling stage refers to the stage when the event propagates from the target node to the window object from bottom to top.
On the inner element click event in example 4, we addedevent.stopPropagation()After this sentence, the execution of the parent event was blocked, and finally only’ inner’ was printed.

inner.onclick = function(ev) {
 console.log('inner');
 ev.stopPropagation();
 };

StopImmediatePropagation can not only prevent the event from bubbling to the parent element, but also prevent other listeners of the same event type of the element from being triggered. However, stopPropagation can only achieve the former effect.. Let’s look at an example:

<body>
 <button id="btn">click me to stop propagation</button>
 </body>
 ......
 const btn = document.querySelector('#btn');
 btn.addEventListener('click', event => {
 console.log('btn click 1');
 event.stopImmediatePropagation();
 });
 btn.addEventListener('click', event => {
 console.log('btn click 2');
 });
 document.body.addEventListener('click', () => {
 console.log('body click');
 });
 // btn click 1

As shown above, after using stopImmediatePropagation, when a button is clicked, not only does the body binding event not trigger, but also another click event of the button does not trigger.

  • event.target & event.currentTarget

To be honest, the difference between the two is not easy to describe in words. Let’s look at an example first:

<div id="a">
 <div id="b">
 <div id="c">
 <div id="d"></div>
 </div>
 </div>
 </div>
 <script>
 document.getElementById('a').addEventListener('click', function(e) {
 console.log(
 'target:' + e.target.id + '&currentTarget:' + e.currentTarget.id
 )
 })
 document.getElementById('b').addEventListener('click', function(e) {
 console.log(
 'target:' + e.target.id + '&currentTarget:' + e.currentTarget.id
 )
 })
 document.getElementById('c').addEventListener('click', function(e) {
 console.log(
 'target:' + e.target.id + '&currentTarget:' + e.currentTarget.id
 )
 })
 document.getElementById('d').addEventListener('click', function(e) {
 console.log(
 'target:' + e.target.id + '&currentTarget:' + e.currentTarget.id
 )
 })
 </script>

When we click on the innermost element D, it will output in turn:

target:d&currentTarget:d
 target:d&currentTarget:c
 target:d&currentTarget:b
 target:d&currentTarget:a

As we can see from the output,event.targetPointing to the element that caused the trigger event, andevent.currentTargetIs the event binding element, only the target element clickedevent.targetIs equal toevent.currentTarget.That is to say,event.currentTargetIs always monitoring events, andevent.targetIs the real sender of the incident.

V. Reference Articles