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

  1. You cannot add more than one handler of the same type
  2. 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:

  1. How to get the content: e.target.innerhtml;
  2. 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)