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:
- Capture phase
- In the target stage
- 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:
- Add handlers directly to the HTML tag
- DOM 0-level handler
- DOM 2 level handler
- 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:
- If the function is called before it is parsed, an error is reported
- 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:
-
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
-
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
addEventListener(eventName, handler, flag)
To specify an event handler for the invoked elementremoveEventListener(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 withon
Initial, such as click event nameclick
handler
: event handler, which can be an anonymous function or an implementation-defined named functionflag
: Boolean value, desirabletrue || false
; When taketrue
Event 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:
attachEvent(eventName, handler)
: Adds an event handlerdetachEvent(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 removeEventListener
Different, here ison
Initial, 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 name
eventName
Based onon
And DOM 2 level methodseventName
Don’t toon
The 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 handler
this
Property 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 abovetarget
: The element that triggers the eventpreventDefault()
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 truecancelable
Attribute values fortrue
The event object is validstopPropagation()
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:
canceBubble
Property: Boolean type that, when set to true, can cancel event bubbling. Default: falsereturnValue
Property: A Boolean type that, when set to false, cancels the default behavior of the event. The default is truesrcElement
Attribute: the triggering element that points to the event, and the DOMtarget
Properties corresponding totype
Attribute: 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 #