1. The flow of events
The event bubbling
The IE event stream is called event bubbling because events are defined to start with the most specific element (the deepest node in the document tree) and propagate up to the less specific element (the document).
Event capture
Event capture means that the least specific node should receive the event first, and the most specific node should receive the event last.
The DOM event flow
The DOM2 Events specification specifies that the event flow is divided into three phases: event capture, arrival to target, and event bubbling. Event capture occurs first, making it possible to intercept events ahead of time. The actual target element then receives the event. The last stage is bubbling, and events must be responded to at the latest.
2. Event handlers
2.1 HTML event handlers
Basic examples:
<input type="button" value="Click Me" onclick="console.log('Clicked')"/>
Copy the code
Or:
<script>
function showMessage() {
console.log("Hello world!");
}
</script>
<input type="button" value="Click Me" onclick="showMessage()"/>
Copy the code
- The value of the property is JavaScript code
- The code executed by the event handler can access everything in the global scope.
This refers to the element itself
<! -- output "Click Me" -->
<input type="button" value="Click Me" onclick="console.log(this.value)">
Copy the code
Defect:
- The first is timing. It is possible that the HTML element is already displayed on the page, the user is interacting with it, and the event handler code is not yet executable.
- Another problem is that extending the event handler scope chain can lead to different results in different browsers.
- The final issue is the strong coupling of HTML and JavaScript.
2.2 DOM0 event handler
Basic examples:
let btn = document.getElementById("myBtn");
btn.onclick = function() {
console.log("Clicked");
};
Copy the code
Note that the previous code does not assign a value to the event handler until after it runs. Therefore, if the above code appears after the button on the page, it is possible that the user clicks the button and does not respond.
When assigning an event handler in DOM0 mode like this, the assigned function is treated as the element’s method. Therefore, the event handler runs in the scope of the element, that is, this equals the element. The following example demonstrates using the this reference element itself:
let btn = document.getElementById("myBtn");
btn.onclick = function() {
console.log(this.id); // "myBtn"
};
Copy the code
Assign the event binding to NULL to remove the event binding
btn.onclick = null; // Remove the event handler
Copy the code
If the event handler is specified in HTML, the value of the onclick attribute is a function that wraps the value of the corresponding HTML event handler attribute. These event handlers can also be removed by setting the corresponding property to NULL in JavaScript.
2.3 DOM2 event Handler
DOM2 Events defines two methods for assigning and removing event handlers: addEventListener() and removeEventListener(). These two methods are exposed on all DOM nodes, and they receive three parameters: the event name, the event handler, and a Boolean value, true for calling the event handler during the capture phase and false (the default) for calling the event handler during the bubble phase.
- The basic example points to this
let btn = document.getElementById("myBtn");
btn.addEventListener("click".() = > {
console.log(this.id); // myBtn, this refers to the element
}, false);
Copy the code
- Add multiple event handlers:
let btn = document.getElementById("myBtn");
btn.addEventListener("click".() = > {
console.log(this.id);
}, false);
btn.addEventListener("click".() = > {
console.log("Hello world!");
}, false);
Copy the code
Multiple event handlers are fired in additive order, so the previous code prints the element ID and then displays the message “Hello World!” .
- Remove the event handler
Event handlers added via addEventListener() can only be removed using removeEventListener() and passing in the same parameters as when they were added. This means that anonymous functions added using addEventListener() cannot be removed, as shown in the following example:
Anonymous functions cannot be removed:
let btn = document.getElementById("myBtn");
btn.addEventListener("click".() = > {
console.log(this.id);
}, false);
// Other code
btn.removeEventListener("click".function() { // No effect!
console.log(this.id);
}, false);
Copy the code
The same function name can be removed:
let btn = document.getElementById("myBtn");
let handler = function() {
console.log(this.id);
};
btn.addEventListener("click", handler, false);
// Other code
btn.removeEventListener("click", handler, false); // It works!
Copy the code
Examples of capturing and bubbling:
#outer {
width: 200px;
height: 200px;
background-color: aqua;
}
#inner {
width: 100px;
height: 100px;
background-color: blueviolet;
}
Copy the code
<div id='outer'>
<div id='inner'></div>
</div>
Copy the code
/* outer, inner */
// Triggers in the bubbling phase
document.getElementById('inner').addEventListener('click', showId);
// This is triggered during the capture phase
document.getElementById('outer').addEventListener('click', showId, true);
function showId() {
alert(this.id);
}
Copy the code
2.3 IE Event Handler
IE implements methods similar to DOM, namely attachEvent() and detachEvent(). Both methods take the same two parameters: the name of the event handler and the event handler function. Because IE8 and earlier only support event bubbling, event handlers added using attachEvent() are added to the bubbling phase.
- The basic example points to this
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick".function() {
console.log("Clicked");
});
Copy the code
With DOM0, the this value in the event handler is equal to the target element. With attachEvent(), the event handler runs in the global scope, so this equals window. Consider the following example using attachEvent() :
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick".function() {
console.log(this= = =window); // true
});
Copy the code
- Add multiple events that fire in the reverse order of addition
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick".function() {
console.log("Clicked");
});
btn.attachEvent("onclick".function() {
console.log("Hello world!");
});
Copy the code
- Remove the event and pass the same reference. Anonymous functions cannot remove it
var btn = document.getElementById("myBtn");
var handler = function() {
console.log("Clicked");
};
btn.attachEvent("onclick", handler);
// Other code
btn.detachEvent("onclick", handler);
Copy the code
2.4 Cross-browser event handlers
Encapsulate a generic event handler
var EventUtil = {
addHandler: function(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on"+ type] = handler; }},removeHandler: function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
cun'za
};
Copy the code
Use:
let btn = document.getElementById("myBtn")
let handler = function() {
console.log("Clicked");
};
EventUtil.addHandler(btn, "click", handler);
// Other code
EventUtil.removeHandler(btn, "click", handler);
Copy the code
There are still execution order issues, so use frameworks or other libraries instead.
3. Event objects
When an event occurs in the DOM, all relevant information is collected and stored in an object called Event. This object package contains some basic information, such as the element that caused the event, the type of event that occurred, and any other data that might be relevant to a particular event. For example, events caused by mouse actions generate mouse position information, while events caused by keyboard actions generate information about the key being pressed. All browsers support this event object, although in different ways.
Basic examples:
let btn = document.getElementById("myBtn");
btn.onclick = function(event) {
console.log(event.type); // "click"
};
btn.addEventListener("click".(event) = > {
console.log(event.type); // "click"
}, false);
Copy the code
- Event properties and methods
- currentTarget, target
Inside the event handler, this is always equal to Event.currenttarGet, which is equal to the element bound to the event handler. Event.target will be equal to the element that actually triggered the event.
document.body.onclick = function(event) {
console.log(event.currentTarget === document.body); // true
console.log(this= = =document.body); // true
console.log(event.target === document.getElementById("myBtn")); // true
};
Copy the code
- preventDefault()
The preventDefault() method is used to prevent the default action for a particular event. For example, the default behavior of a link is to navigate to the URL specified by the href attribute when clicked. If you want to block this navigation behavior, you can cancel it in the onclick event handler, as shown in the following example:
let link = document.getElementById("myLink");
link.onclick = function(event) {
event.preventDefault();
};
Copy the code
The event object preventDefault() has the cancelable property set to true for any event with preventDefault().
- stopPropagation()
The stopPropagation() method is used to immediately stop the event stream from propagating through the DOM structure, canceling subsequent event capture or bubbling. For example, a call to stopPropagation() added directly to the button’s event handler prevents the registered event handler on Document.body from executing. Such as:
let btn = document.getElementById("myBtn");
btn.onclick = function(event) {
console.log("Clicked");
event.stopPropagation();
};
document.body.onclick = function(event) {
console.log("Body clicked");
};
Copy the code
After preventing bubbling, the click event for the body binding is not triggered
IE event object omitted
4. Event type
DOM3 Events defines the following event types:
- User interface events (UIEvent) : Generic browser events that involve interaction with a BOM.
- Focusevents: Fired when an element gains and loses focus.
- Mouseevents: Triggered when the mouse is used to perform some action on the page.
- Wheelevents: Triggered when a mouse wheel (or similar device) is used.
- InputEvent (InputEvent) : emitted when text is entered into a document.
- KeyboardEvent: Triggered when the keyboard is used to perform some action on the page.
- Compostion Event: Emitted when a character is entered using an Input Method Editor (IME).
4.1 User Interface Events
- Load: triggered on a window when the page has finished loading
<frameset>
) when all panes (<frame>
) are triggered after loading is complete, inThe element is fired when the image is loaded, and the element is fired when the corresponding object is loaded.- On the Window object, the load event fires after the entire page (including all external resources such as images, JavaScript files, and CSS files) has loaded. Load event handlers can be specified in two ways. The first is JavaScript, as shown below:
window.addEventListener("load".(event) = > { console.log("Loaded!"); }); Copy the code
The second way to specify a load event handler is to add the onload attribute to the element. Events added to the window, event.target, are equal to document:
<body onload="console.log('Loaded! ')"> Copy the code
- The load event is also triggered on the image
<img src="smile.gif" onload="console.log('Image loaded.')"> Copy the code
let image = document.getElementById("myImage"); image.addEventListener("load".(event) = > { console.log(event.target.src); }); Copy the code
- Unload: Fires at window when the page has been completely unloaded, or at window sleeve when all panes have been unloaded, or at
<object>
Element emitted when the corresponding object has been unloaded. - Abort:
<object>
Element when the user prematurely terminates the download of the corresponding object before it has finished loading. - Error: Raised when JavaScript fails at a window
<img>
Element when the specified image cannot be loaded<object>
Element when the corresponding object cannot be loaded, and in a window sleeve when one or more panes cannot complete loading. - Select: in the text box (Or textarea) when the user selects one or more characters.
- Resize: Triggered when a window or pane is scaled.
- Scroll: Triggered on an element that contains a scrollbar when the user scrolls it.
<body>
The element contains a scroll bar for the loaded page. Most HTML events are related to window objects and form controls. - Blur: Triggered when an element loses focus. This event does not bubble and is supported by all browsers.
- Focus: Fires when the element gains focus. This event does not bubble and is supported by all browsers.
- Focusin: Fires when the element gains focus. This event is the bubbling version of focus.
- Focusout: Fires when an element loses focus. This event is a generic version of Blur.
These Events are classified as HTML Events in DOM2 Events.
4.2 Focus Events
The two main events in focus events are focus and blur, which have been supported by browsers since the early days of JavaScript. Their biggest problem is that they don’t bubble. This later led to The addition of FocusIn and FocusOut in IE, and DOMFocusIn and DOMFocusOut in Opera. The two Events added to IE have been standardized by DOM3 Events.
When the focus shifts from one element on the page to another, the following events occur in sequence.
(1) Focuscout is triggered on elements that lose focus. (2) FocusIn fires on the element that gets focus. (3) Blur triggers on elements that are out of focus. (4) Focus is triggered on the element that gets the focus.Copy the code
Where, the event targets of blur, and FocusOut are the elements that lose focus, while the event targets of focus, and FocusIn are the elements that gain focus.
4.3 Mouse and Scroll Events
DOM3 Events defines nine mouse Events.
- Click: Triggered when the user clicks the primary mouse key (usually the left) or presses the enter key on the keyboard. This is primarily for accessibility reasons, allowing both the keyboard and mouse to trigger the onclick event handler.
- Dblclick: Triggered when the user double-clicks the primary (usually left) mouse button. This event is not defined in DOM2 Events, but is well supported, and DOM3 Events standardizes it.
- Mousedown: Triggered when the user presses any mouse key. This event cannot be triggered by the keyboard.
- Mouseenter: Triggered when the user moves the mouse cursor from outside the element to inside it. This event does not bubble and is not triggered when the cursor passes over a descendant element. The MouseEnter event is not defined in DOM2 Events but is a new event in DOM3 Events.
- Mouseleave: Triggered when the user moves the mouse cursor from inside an element to outside it. This event does not bubble and is not triggered when the cursor passes over a descendant element. The Mouseleave event is not defined in DOM2 Events but is a new event in DOM3 Events.
- Mousemove: Triggers repeatedly as the mouse cursor moves over the element. This event cannot be triggered by the keyboard.
- Mouseout: Triggered when the user moves the mouse cursor from one element to another. The element you move to can be an external element or a child of the original element. This event cannot be triggered by the keyboard.
- Mouseover: Triggered when the user moves the mouse cursor from outside the element to inside it. This event cannot be triggered by the keyboard.
- Mouseup: Triggered when the user releases the mouse key. This event cannot be triggered by the keyboard.
All elements in the page support mouse events. With the exception of mouseEnter and Mouseleave, all mouse events bubble up and can be cancelled, which affects the default behavior of the browser. Because of the relationships between events, the default behavior of canceling mouse events affects other events as well. For example, the click event is triggered only if a MouseDown event is triggered, followed by a Mouseup event on the same element. If either of the mouseDown and mouseup events are cancelled, the Click event will not fire. Similarly, two consecutive click events cause the DBLClick event to fire. The dBLClick event will not occur as long as any logic prevents both click events from occurring (such as canceling either click or either mouseDown or Mouseup). These four events will always fire in the following order:
(1) mousedown
(2) mouseup
(3) click
(4) mousedown
(5) mouseup
(6) click
(7) dblclick
Copy the code
MouseEvents in DOM3 Events correspond to type “MouseEvent”, not “MouseEvents”. Mouse events also have a subcategory called wheel events. There is only one event, mousewheel, which reflects the interaction of the wheel on a mousewheel or similar device with a wheel.
4.3.1 Page coordinates
4.3.2 modifier keys
Although mouse events are primarily triggered by the mouse, sometimes it is necessary to consider the shape of the keyboard keys to determine what the user wants to do. The keyboard modifier keys Shift, Ctrl, Alt, and Meta are often used to modify the behavior of mouse events. DOM specifies four attributes to represent the state of these modifier keys: shiftKey, ctrlKey, altKey, and metaKey. These attributes will contain Boolean values true when the modifier key is pressed and false when the modifier key is not pressed. You can use these properties to check whether the modifier key was pressed during a mouse event.
let div = document.getElementById("myDiv");
div.addEventListener("click".(event) = > {
let keys = new Array(a);if (event.shiftKey) {
keys.push("shift");
}
if (event.ctrlKey) {
keys.push("ctrl");
}
if (event.altKey) {
keys.push("alt");
}
if (event.metaKey) {
keys.push("meta");
}
console.log("Keys: " + keys.join(","));
});
Copy the code
4.3.3 Mouse Buttons
For mouseDown and Mouseup events, the event object has a button property that indicates which key was pressed or released. DOM defines three values for the Button property: 0 for the primary mouse key, 1 for the middle mouse key (which is usually also a wheel key), and 2 for the secondary mouse key.
let div = document.getElementById('myDiv')
div.onmousedown = event= > console.log(event.button)
Copy the code
4.3.4 Additional Event Information
The DOM2 Events specification provides the detail property on the event object to give more information about the event.
4.3.5 mousewheel event
The Event object for the MouseWheel event contains all the standard information for mouse events, in addition to a new property called wheelDelta. When the mouse wheel is rolled forward (up), wheelDelta is +120 each time; When the mouse wheel is rolled back (down), wheelDelta is -120 each time
document.addEventListener("mousewheel".(event) = > {
console.log(event.wheelDelta);
});
Copy the code
4.4 Keyboard and Input Events
Keyboard events contain three events:
- Keydown: triggered when the user presses a key on the keyboard, and repeatedly triggered when the user holds down the key.
- Keypress, which is triggered when the user presses a key on the keyboard and produces a character. The Esc key also triggers this event. DOM3 Events discards keypress Events in favor of textInput Events.
- Keyup, triggered when the user releases a key on the keyboard.
While all elements support these events, they are easiest to see when the user is typing something into a text box.
There is only one input event, textInput. This event is an extension of the KeyPress event to make it easier to intercept text input before it is displayed to the user. TextInput fires before text is inserted into the text box. When the user presses a character key on the keyboard, the keyDown event is triggered, then the KeyPress event is triggered, and finally the KeyUp event is triggered. Note that the KeyDown and KeyPress events fire before the text box changes, and the keyUp event fires after the text box changes. If a character key is held down, keyDown and keyPress fire repeatedly until the key is released. For non-character keys, pressing the key on the keyboard triggers the KeyDown event and then the KeyUp event. If you hold down a non-character key, the keyDown event is repeatedly emitted until the key is released, at which point the KeyUp event is emitted.
Keyboard events support the same modifier keys as mouse events. The shiftKey, ctrlKey, altKey, and metaKey attributes in the event are all available in keyboard events.
4.4.1 key code
For keydown and keyup events, the keyCode property of the event object stores a keyCode corresponding to a specific key on the keyboard. For letter and number keys, the value of keyCode is consistent with the ASCII encoding of lowercase letters and numbers. For example, the number 7 key has A keyCode of 55, while the letter A key has A keyCode of 65.
let textbox = document.getElementById("myText");
textbox.addEventListener("keyup".(event) = > {
console.log(event.keyCode);
});
Copy the code
Non-character key key code:
4.4.2 the DOM3 change
The DOM3 Events specification defines two new properties, key and CHAR. The key property is used instead of keyCode and contains a string. When a character key is pressed, the value of key is equal to a text character (such as “k” or “M”); When a non-character key is pressed, the value of key is the key name (such as “Shift” or “ArrowDown”). The char attribute is similar to key when a character key is pressed and null when a non-character key is pressed.
let input = document.getElementById('input')
input.onkeydown = event= > console.log(event.key)
Copy the code
4.4.3 (event
As an alternative to keyPress, the textInput event behaves a little differently.
- One difference is that keypress fires on any element that can get focus, whereas textInput fires only on editable areas.
- Another difference is that textInput fires only when a new character is inserted, whereas keypress fires for any key that might affect the text (including backspace).
Because the textInput event is primarily concerned with characters, a data property is provided on the Event object that contains the character to be inserted (not the character encoding). The value of data is always the character to be inserted, so if Shift is not pressed when S is pressed, data is “S”, but if Shift is pressed when S is pressed, data is “S”.
let textbox = document.getElementById("myText");
textbox.addEventListener("textInput".(event) = > {
console.log(event.data);
});
Copy the code
4.4.4 change event
Fired when the value of the and
4.5 HTML 5 events
4.5.1 contextmenu event
The ContextMenu event bubbles, so you can handle all of the same events on the page simply by specifying an event handler for the document. The event target is the element that triggers the action. This event can be cancelled on all browsers, use event.preventDefault() in DOM compliant browsers. A simple example:
<div id="myDiv">Right click or Ctrl+click me to get a custom context menu.
Click anywhere else to get the default context menu.</div>
<ul id="myMenu" style="position:absolute; visibility:hidden; background-color: silver">
<li><a href="http://www.somewhere.com"> somewhere</a></li>
<li><a href="http://www.wrox.com">Wrox site</a></li>
<li><a href="http://www.somewhere-else.com">somewhere-else</a></li>
</ul>
Copy the code
window.addEventListener("load".(event) = > {
let div = document.getElementById("myDiv");
div.addEventListener("contextmenu".(event) = > {
event.preventDefault();
let menu = document.getElementById("myMenu");
menu.style.left = event.clientX + "px";
menu.style.top = event.clientY + "px";
menu.style.visibility = "visible";
});
document.addEventListener("click".(event) = > {
document.getElementById("myMenu").style.visibility = "hidden";
});
});
Copy the code
4.5.2 beforeunload events
Beforeunload events are triggered on Windows to give developers an opportunity to prevent pages from being unloaded. This event is triggered when the page is about to be uninstalled from the browser, but not if the page needs to continue to be used. This event cannot be cancelled, otherwise it means the user can be permanently blocked from a page. Instead, this event displays a confirmation box to the user with a message indicating that the browser is about to uninstall the page and asking the user to confirm whether they want to close the page or stay on it.
4.5.3 DOMContentLoaded event
The Window load event fires after the page is fully loaded, which can take a long time due to waiting for many external resources to complete. Instead of waiting for images, JavaScript files, CSS files, or other resources to load, the DOMContentLoaded event fires as soon as the DOM tree is built. In contrast to load events, DOMContentLoaded allows developers to specify event handlers at the same time as external resources are downloaded, allowing users to interact with the page more quickly.
4.5.4 hashchange
HTML5 has added a Hashchange event to notify developers when the URL hash value (the part after the last # of the URL) changes. This is because developers often use URL hash values in Ajax applications to store state information or route navigation information. The onHashChange event handler must be added to the window and called every time the URL hash value changes. The Event object has two new properties: oldURL and newURL. These two attributes hold the urls before and after the change, respectively, and are the full urls with hash values. The following example shows how to get a before and after URL:
window.addEventListener("hashchange".(event) = > {
console.log(`Old URL: ${event.oldURL}, New URL: ${event.newURL}`);
});
Copy the code
If you want to determine the current hash value, it is best to use the location object:
window.addEventListener("hashchange", (event) => {
console.log(`Current hash: ${location.hash}`);
});
Copy the code
5. Memory and performance
In JavaScript, the number of event handlers on a page is directly related to the overall performance of the page. There are many reasons.
- First, each function is an object and occupies memory space, and the more objects there are, the worse performance there is.
- Second, specifying the number of times the event handler needs to access the DOM can preemptively delay the entire page interaction.
You can improve page performance by paying more attention to methods when using event handlers.
5.1 Event Delegation
The solution to “too many event handlers” is to use event delegates. Event delegation utilizes event bubbling to manage one type of event with just one event handler.
Example:
<ul id="myLinks">
<li id="goSomewhere">Go somewhere</li>
<li id="doSomething">Do something</li>
<li id="sayHi">Say hi</li>
</ul>
Copy the code
let list = document.getElementById("myLinks");
list.addEventListener("click".(event) = > {
let target = event.target;
switch (target.id) {
case "doSomething":
document.title = "I changed the document's title";
break;
case "goSomewhere":
location.href = "http:// www.wrox.com";
break;
case "sayHi":
console.log("hi");
break; }});Copy the code
5.2 Deleting event Handlers
By assigning an event handler to an element, a link is established between the browser code and the JavaScript code responsible for page interaction. The more connections you make, the worse your page performance will be. In addition to limiting such connections through event delegates, unused event handlers should be removed in a timely manner. Many Web applications suffer from poor performance due to useless event handlers lingering in memory. There are two main reasons for this problem.
- The first is to remove the element with the event handler.
Such as removeChild() or replaceChild(), a real DOM method to remove a node. The most common way to replace a part of a page is with innerHTML as a whole. At this point, an element removed from innerHTML that has an event handler on it will not be properly cleaned up by the garbage collector.
- Another problem that can cause residual references in memory is page unloading.
Again, IE8 and earlier have a lot of problems in this case, but it seems to affect all browsers. If event handlers are not cleaned up after the page is unloaded, they remain in memory. After that, the number of residual objects in memory increases each time the browser loads and unloads the page (such as by moving forward, backward, or refreshing), because the event handler is not recycled.
In general, it is best to remove all event handlers in the OnUnload event handler before the page is unloaded. This is also a good time to use event delegates, because there are few event handlers, so it’s easy to remember which ones to delete. One thing to remember about cleaning up when a page is unloaded is that what is done in the OnLoad event handler is best recovered in the OnUnload event handler.