Browser event model
The process in the browser event model is divided into three phases: capture phase, target phase, and bubble phase.
How to bind events
There are three ways to bind events: inline binding, direct assignment, and addEventListener
Industry:
<button onclick="handleClick()">Press me</button>
Copy the code
This method is not recommended.
Direct assignment
var btn = document.querySelector('button');
btn.onclick = function() {
console.log('button clicked')
}
Copy the code
The above approach is not recommended because it has two drawbacks
- You cannot add more than one handler of the same type
- There is no control over which phase is executed, which will be covered later in event capture/bubbling. This can also be done with addEventListener.
So addEventListener came out of the blue, and that’s what’s recommended today.
addEventListener
Window.addeventlistener ("click", function (e) {console.log("window capture ", e.target.nodename, e.currenttarget.nodename); }, true);Copy the code
It takes three parameters: event name type, event specific action function, and capture/bubble
Capture: The event streams down from the top, assuming there are three elements, parent, Child, and son. If I click on the son element, then the elements on parent and Child will execute as well.
Bubbling: Events flow from the bottom up
const parent = document.getElementById("parent"); const child = document.getElementById("child"); const son = document.getElementById("son"); Window.addeventlistener ("click", function (e) {console.log("window capture ", e.target.nodename, e.currenttarget.nodename); }, true); Parent. AddEventListener ("click", function (e) {console.log("parent capture ", e.target.nodename, e.currenttarget.nodename); }, true); Child.addeventlistener ("click", function (e) {console.log("child catch ", e.target.nodename, e.currenttarget.nodename); }, true); Son.addeventlistener ("click", function (e) {console.log("son catch ", e.target.nodename, e.currenttarget.nodename); }, true); Window.addeventlistener ("click", function (e) {console.log("window bubble ", e.target.nodename, e.currenttarget.nodename); }, false);Copy the code
Print:
Note:
- When the third argument is not passed, the default is false, that is, bubbling.
- For browser compatibility, Internet Explorer does not have addEventListener. AttachEvent and detachEvent respectively.
- NodeName specifies the element currently clicked. E. currenttarget. NodeName binds the element listening for the event
Preventing an event from spreading
- e.stopPropagation()
One of the things you hear a lot about is preventing bubbling, but this actually prevents not only bubbling, but also the propagation of the capture phase.
- stopImmediatePropagation()
If there are multiple event listeners of the same type of event bound to the same element, when events of that type are fired, they are executed in the order in which they were added. If one monitor function performs the event stopImmediatePropagation () method, which is the rest of the current element to monitor function will not be executed.
function stopPropagation(ev) { if (ev.stopPropagation) { ev.stopPropagation(); W3c} else {ev.cancelBubble = true; // IE } }Copy the code
Note: Ie does not support event capture and can only prevent event bubbling, but the standard W3C does.
Cancels the default behavior of the event
- e.preventDefault()
E.preventdefault () prevents the default behavior of the event, such as clicking the A TAB to jump to another page, dragging an image to the browser to open automatically, clicking the submit button on a form to submit the form, etc., because sometimes we don’t want these things to happen, so we need to prevent the default behavior
function preventDefault(event) { if (event.preventDefault) { event.preventDefault(); // w3c} else {event.returnValue = false; // IE } }Copy the code
Note: the main consideration is browser compatibility.
- AttachEvent — Compatible with IE7 and IE8; A third parameter is not supported to control which phase occurs, the default is bound to the bubble phase
- AddEventListener — Compatible with Firefox, Chrome, IE, Safari, Opera;
Event delegation
How it works: Events bubble up
<ul id="ul">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
</ul>
Copy the code
Description: For a set of elements, we want to click on the corresponding element to print out the corresponding content and index.
Think: What would you do? Like this?
const liList = document.getElementsByTagName("li"); for(let i = 0; i<liList.length; I ++){liList[I]. AddEventListener ('click', function(e){alert(' contents = ${e.target.innerhtml}, index = ${I} '); })}Copy the code
Find all elements and add events to each element. Consider: this is obviously fine, but the performance is poor, and looping over DOM elements is a performance drain.
We should bind events in ul: this way!
Think about:
- How to get the content: e.target.innerhtml;
- How to take the index, the index = Array. Prototype. IndexOf. Call (liList, target);
const ul = document.querySelector("ul"); Ul.addeventlistener ('click', function (e) {const target = e.target; If (target. TagName. ToLowerCase () = = = "li") {const liList = this. QuerySelectorAll (" li "); The index = Array. Prototype. IndexOf. Call (liList, target); Alert (' contents ${target.innerhtml}, index ${index} '); }})Copy the code
Note: Array. Prototype. IndexOf. Call (liList, target) is equivalent to liList. IndexOf (target)