The interaction between JavaScript and HTML is achieved through events, so it is essential to understand the basics of events. This article will discuss some aspects of JavaScript events, including event flow, event handlers, event objects, and event delegates, which make up sections 1 to 4 of this article respectively.

A flow of events

It is known that the DOM nodes of web pages constitute a tree structure, which is called DOM tree.

And it knows that when a node on the page fires an event, it’s not just the node that gets notified of the event, but all elements along the DOM tree from the Document to the node itself can get notified of the event, but in a sequential order. The event stream describes the order in which elements in the DOM tree receive event notifications.

Different browser vendors implement different or even opposite directions for event flow, which can be divided into two types: bubbling flow and capture flow. Interestingly, these two streams of events are almost completely opposite, and they are discussed separately below. We also discuss the three stages of the event flow specified by the DOM.

1.1 Event Bubbling

IE’s stream of events is called Event Bubbling, and as the name suggests, it comes from the bottom up. That is, from the lower level of the DOM tree to the upper level, from concrete elements to less concrete elements, or from child elements to parent elements.

For example, in the following DOM structure (indentation indicates the hierarchy of nodes) :

    html
        head
        body
            div
Copy the code

The DOM tree structure and bubbling event flow directions look like this:

If the event of the above div element is triggered, the elements and order in which the event is notified are as follows:

div -> body -> html -> document
Copy the code

1.2 Event Capture

In contrast to bubbling flow, the idea of event capture is propagated from the top of the DOM tree to the node itself that triggers the event, that is, from less concrete elements to concrete elements, or from parent elements to child elements, so to speak.

Taking the DOM structure in the above section as an example, the schematic diagram of event capture flow is as follows:

That is, if an event is triggered on a div element, the elements are notified of the event in the order:

document -> html -> body -> div
Copy the code

Although the event is triggered on the DIV, it is notified of the event last.

1.3 DOM event flow

The event flow specified by DOM2-level events is divided into three stages, namely:

  1. Capture phase
  2. In the target stage
  3. Bubbling phase

That is, the flow of events specified at the DOM2 level includes the flow of events that bubble and capture in two different directions, plus a phase that is on target.

It is important to note that the capture phase defined at DOM2 level does not occur to the element itself that triggers the event, but only to its upper nodes; The target phase occurs only on the element that triggered the event; The bubble phase is the widest and covers everything from the element itself that triggers the event to the top of the DOM tree.

Again using the DOM structure from Section 1.1 as an example, the three phases are clearer from the following diagram (the extraneous head nodes have been omitted for convenience) :

As you can see from above, the capture phase stops from the root node to the body node; Being in the target phase only happens to div; The bubble phase is the notification from the div all the way to the root node.

Although DOM rules do not refer to target elements during the capture phase, most browsers do not follow this rule and refer to target elements, as shown below:

2 Event handlers

There are several ways to add event handlers:

  1. Add handlers directly to the HTML tag
  2. DOM 0-level handler
  3. DOM 2 level handler
  4. IE event handler

2.1 Handle events directly in HTML tags

You can specify the event handler directly with onXXX in an HTML tag, for example, to output a string when an element is clicked:

<div onclick="console.log('div is clicked'); alert('clicked')"></div>
Copy the code

Div is clicked from the console and clicked from the window.

You can also call code from other parts of the page, such as calling a function defined in the script tag:

Function fn(){console.log(this + 'calls the function fn! '); } </script> <! <div onclick="fn()"></div>Copy the code

Note: You will not normally use this method to handle events directly because of the following disadvantages:

  1. If the function is called before it is parsed, an error is reported
  2. This can lead to strong coupling between HTML and JavaScript, which can be difficult to change

2.2 DOM 0-level event handlers

This method specifies the event handler by adding on to the event name, for example

element.onClick = handler
Copy the code

For a more concrete example, get an element on the page with id container and specify the handler for the click event:

<! Let target = document.getelementById ('target'); let target = document.getelementById ('target'); Target.onclick = function(){console.log('div#target is clicked'); } </script>Copy the code

When you click on div#target, the console prints div#target is clicked.

2.2.1 Unbind event handlers

An event handler can be specified as NULL to unbind the event handler originally specified for the element, for example, to unbind the hit handler for the target above:

// Unbind the handler for the click event
target.onclick = null;
Copy the code

So clicking on the element again won’t do anything

2.2.2 note

This way of specifying event handlers has the following characteristics and points to note:

  1. The “this” attribute in the event handler refers to the element itself, so we can refer to its attributes directly. For example, we can add three class names to the target element in the previous example and use this attribute to get its class name in the event handler:

    <div id="target" class="cname1 cname2 cname3"></div>
    
    target.onclick = function(){
        console.log(this.className);
    }
    Copy the code

    When hit div#target, the console prints: cname1 cname2 cname3

  2. This method can specify only one event handler, which will override the previous one, for example:

    // Specify the handler for the first hit event to target
    target.onclick = function(){
        console.log('I was the first.');
    }
    
    // Specify the handler for the second click event to target
    target.onclick = function(){
        console.log('I'm the second one');
    }
    
    // I'm the second one when I hit target
    Copy the code

    From the above experiment, you can see that the handler defined later overrides the previous one.

2.3 DOM level 2 handler

DOM level 2 defines two functions to bind and unbind event handlers to an element, respectively

  1. addEventListener(eventName, handler, flag)To specify an event handler for the invoked element
  2. removeEventListener(eventName, handler, flag)To specify an event handler for the invoked element

Both functions take three arguments:

  • eventName: Indicates the event name. Note that the event name does not start withonInitial, such as click event nameclick
  • handler: event handler, which can be an anonymous function or an implementation-defined named function
  • flag: Boolean value, desirabletrue || false; When taketrueEvent handlers are called during the capture phase, or otherwise during the bubble phase

For example, add an event handler for the element div#target using this method:

target.addEventListener('click'.function(){
    console.log('I'm the event handler that addEventListener added');
}, false);
// When you hit target, it says: I am the event handler that addEventListener added
Copy the code

The event handler above is called during the bubble phase because the third parameter flag is false

Again, remove an event handler from an element with removeEventListener:

// Add an event handler
target.addEventListener('click', handler, false);
// Clicking on target before writing the following code will output 'I am an event handler'

// Cancel the event handler
target.removeEventListener('click', handler, false);
// Now when you click on the target element, there is no response

// This function is called as an event handler
function handler(){
    console.log('I'm an event handler');
}
Copy the code

2.3.1 note

This method of adding and removing event handlers has the following characteristics:

  • Multiple event handlers can be added, and are fired in the order in which they were added

    // Add two event handlers
    target.addEventListener('click'.function(){
        console.log('I'm the first event handler');
    }, false);
    
    target.addEventListener('click'.function(){
        console.log('I'm the second event handler');
    }, false);
    
    /* Clicking on the target element prints I'm the first event handler I'm the second event handler */
    Copy the code
  • When removeEventListener is used to cancel an event handler for an element, the argument must correspond exactly to the argument of the corresponding addEventListener. This means that anonymous functions cannot be cancelled because each anonymous function is not the same:

    target.addEventListener('click'.function(){
        console.log(1);
    }, false);
    
    // Try to cancel the event handler above
    target.removeEventListener('click'.function(){
        console.log(1);
    }, false);
    
    // Clicking target still outputs 1, because removeEventListener is the anonymous function of the event handler
    // Not the same as the event handlers in addEventListener, although they have the same behavior defined internally
    Copy the code

    So, if you want to cancel an event handler at any time, don’t use anonymous functions.

2.4 IE event Handler

IE implements two methods similar to dom2-level:

  1. attachEvent(eventName, handler): Adds an event handler
  2. detachEvent(eventName, handler): Unties event handlers

Both functions take two arguments:

  • eventName: Event name,Notice the name of the event and the two DOM level methodsAddEventListener and removeEventListenerDifferent, here isonInitial, such as click event nameonclick
  • handler: event handler, which can be an anonymous function or an implementation-defined named function

Against 2.4.1 note

There are a few things to note about these two event handlers in IE:

  • The first parameter is the event nameeventNameBased ononAnd DOM 2 level methodseventNameDon’t toonThe beginning of the different
  • You can also add multiple event handlers, but the ones you add later will be called first, which is still different from DOM 2 level methods
  • Of the event handlerthisProperty refers to the global object, not the current element
  • Event handlers are invoked only in the bubble phase, not in the event capture phase

When writing cross-browser event handlers, to maintain consistency with Internet Explorer, set the third parameter of the two DOM level methods to false to be called during the event bubble phase.

3 Event Object

When an event is raised, an event object is generated that contains all information about the current event and is passed into the event handler to get all information about the event.

All browsers support event objects, but the specific implementation is different, can be divided into DOM event objects and IE event objects.

3.1 Event objects in the DOM

Both DOM0 and DOM2 levels support event objects and behave the same.

For example, in passing the event object as event and accessing one of its properties in the event handler:

target.addEventListener('click'.function(event){
    console.log('The event.type in DOM 2 level is:' + event.type);
}, false);

target.onclick = function(event){
    console.log('The event.type in DOM 0 is:' + event.type);
}

/* The event. Type in DOM 2 is click. The event. Type in DOM 0 is click
Copy the code

The above results show that there is no difference in the value of the type attribute of the event object in the specified methods of the two events.

DOM event objects have many properties and methods that can be accessed and used. Here are a few common examples. For more information, visit the Little Red Book.

  • currentTarget: Which element is the current event handler on which events are processed on multiple elements due to the event flow, as described in section 1 above
  • target: The element that triggers the event
  • preventDefault()Function: The default behavior of the cancel event. The most familiar use of this function is to cancel linked elements<a>If this function is used, click<a>The link will not automatically jump. Note: Only truecancelableAttribute values fortrueThe event object is valid
  • stopPropagation()Function: Cancel the event to continue bubbling or trapping

The currentTarget attribute and the target attribute are worth distinguishing. Simply put, the former can be used to determine where an event has flowed, i.e. where it has been captured or bubbled. The latter can be used to determine what element triggers an event. For example:

Define two nested div elements, both of which print currentTarget and target in event handlers, and observe the difference between the attributes in the two elements:

<div id="outer" style="width: 300px; height: 300px; background-color: brown;" > <div id="inner" style="width: 100px; height: 100px; background-color: cadetblue;" ></div> </div> outer. AddEventListener ('click', function(event){console.log('>> this is outer's event handler '); Console. log(' Now event bubbles up '+ event.currenttarge. id); Console. log(' the initiating element of this event is' + event.target.id); }, false); Inner. AddEventListener ('click', function(event){console.log('>> This is inner's event handler '); Console. log(' Now event bubbles up '+ event.currenttarge. id); Console. log(' the initiating element of this event is' + event.target.id); }, false); /* When the inner element is clicked, the console outputs: >> This is the event handler for inner and now the event handler for outer is bubbling up to inner and the event handler for outer is bubbling up to inner and the event handler for outer is bubbling up to outer and the event handler for outer is bubbling up to inner */Copy the code

You can see that the currentTarget property changes with the flow of events. When the event bubbles to inner, currentTarget points to Outer.

You can also see that the current attribute always points to inner, because inner is the trigger element of the click event, so the target attribute of the event object always points to inner, no matter which element the event bubbles to.

3.2 IE8 and previous event objects

The event object of IE also has its own unique attributes. Although the attribute of the event object before IE8 is different from the attribute name of the event object in DOM, it has a corresponding relationship as follows:

  • canceBubbleProperty: Boolean type that, when set to true, can cancel event bubbling. Default: false
  • returnValueProperty: A Boolean type that, when set to false, cancels the default behavior of the event. The default is true
  • srcElementAttribute: the triggering element that points to the event, and the DOMtargetProperties corresponding to
  • typeAttribute: The value is a data type

When specifying an event handler through DOM 0, the event object is the window’s event property, which is not passed into the event handler function by default:

outer.onclick = function(e){
    var event = window.event;
    console.log(event.src);
}
Copy the code

In IE9 and later, DOM compatible event objects are implemented. So in IE9 and beyond, you can use both DOM event objects and IE’s own unique event objects (MSEventObj). And after IE11, in dom0-level fashion, the event object passed through and the event object fetched from the window point to the same object:

outer.onclick = function(e){
    console.log(e === window.event);  // IE11:true; IE10-IE8: false 
}
Copy the code

4 Event Delegation

The number of event handlers on a page affects the performance of your application because each event handler is an object, and the more objects in memory, the more memory it occupies. Second, more event handlers tend to mean more DOM operations, and the frequency of DOM operations is an important factor in page performance.

Because of the 1. Event stream and 2. The target attribute in the event object always points to the triggering element of the current event itself, the event delegate strategy has been developed to reduce the number of bindings for event handlers on the page.

If you have the following DOM structure:

html
	head
    body
    	div#div1
        div#div2
Copy the code

The corresponding DOM tree is

You can see that the flow of events for div#container and button# BTN both pass through the document element.

If you want to add an event handler to div#container and button# BTN, for example:

div1.addEventListener('click'.function(event){
    console.log('>> This is the event handler for Div1 ');
}, false);

/* If you click div1, it prints: >> This is div1's event handler */


div2.addEventListener('click'.function(event){
    console.log('>> This is the event handler for Div2 ');
}, false);

/* Press div2 to print: >> This is div2 event handler */
Copy the code

The above example adds an event handler to both div elements, but we know that both events flow to the document, so we can use the target attribute of the event object in the Document event handler to determine which element triggered the event and handle it accordingly:

document.addEventListener('click'.function(event){
    switch (event.target.id) {  // Retrieve the id of the event trigger
        case 'div1':  // if the event is triggered by div1
            console.log('>> This is the event handler for Div1 ');
            break;
        case 'div2':  // if the event is triggered by div2
            console.log('>> This is the event handler for Div2 ');
            break;
        default:  
            break; }},false);

/* Click div1, it will print: >> This is the event handler for div1, press div2, it will print: >> This is the event handler for div2 */
Copy the code

As can be seen from the above, flexible use of event flow and event object attributes can complete the event delegate strategy, delegating the events of specific elements to the top element for processing. In this way, although some judgment operations are increased, the number of event handlers in the page can be significantly reduced to achieve the purpose of optimizing performance.

Reference: “JavaScript advanced programming” if there is an error, thank you for correcting ~

After #