JS event details

The interaction between javascript and HTML is achieved through events.

An event is an action performed by the user or the browser itself, such as clicking, loading, mouse moving in and out, and so on.

The DOM event flow

The event flow consists of three phases. In short: events flow from the root of the document to the target object (capture phase), then are fired on the target object (target phase), and then back to the root of the document (bubble phase).

DOM event flow: consists of three phases:

The first Phase of an event is the Capture Phase. Events flow from the root node of the document to the target node of the event along the STRUCTURE of the DOM tree. It passes through various levels of DOM nodes and fires capture events on each node until it reaches the target node of the event. The main task of the capture phase is to establish propagation paths through which events can be traced back to documents and nodes during the bubbling phase.

When an event reaches the Target node, the event enters the Target Phase. Events are fired at the target node (executing the function corresponding to the event) and then backflow until propagated to the outermost document node.

The Bubble Phase does not terminate on the target element after the event is triggered on that element. It bubbles up the DOM tree until it reaches the outermost root node. That is, the same event will occur on the parent node of the target node, and then on the parent node… Until the outermost node is triggered.

All events go through the capture and target phases, but some events skip the bubbling phase. For example, focus events that give an element input focus and blur events that lose input focus do not bubble.

The event type

UI (User Interface) events that are triggered when a User interacts with elements on the page

  • Load, unload, error, Select, resize, scroll

Focus events that are triggered when a page gains or loses focus

  • Lose focus
  • Focus, focusin gain focus

Mouse events are triggered when users perform operations on the page using the mouse

  • Click, dbclick, mousedown, mouseup

  • Mouseenter, mouserleave

  • mousemove

  • Mouseout, mouseover

    Click and double click events are triggered in the following order

    • mousedown
    • mouseup
    • click
    • mousedown
    • mouseup
    • dbclick

Wheel event, triggered when mouse wheel operation is used

  • mousewheel

Text event that is triggered when text is entered in the document

  • TextInput This event is triggered when the user enters a character in an editable area

Keyboard events that are triggered when the user performs an action on the page using the keyboard

  • Keydown This parameter is triggered when you press any key on the keyboard
  • Keypress Is triggered when the character key on the keyboard is pressed
  • Keyup user releases build time trigger on keyboard

HTML 5 events

  • Contextmenu event: Right mouse button brings up contextmenu
  • Beforeunload event: Triggered before the browser unloads the page
  • DOMContentLoad event: Emitted after the complete DOM tree has been formed.
  • Readystatechange event: Provides information about the loading status of the document
  • Pageshow and PageHide events: 👉MDN portal is triggered when a page is displayed and hidden
  • Hashchange event: Triggered when the hash changes

In addition to that, there are mutable events, compound events, some of the new events that HTML5 has added, and I won’t list them all. The full list is available here at Web Events

The event object

👉 Event :MDN portal

When an event on the DOM is triggered, an event object is generated, which contains all the information related to the event. All browsers support event objects, but in different ways.

Common attributes:

Target Indicates the target of the event

CurrentTarget The element of the binding event, pointing to the same object as ‘this’

StopPropagation () Cancels further capture or bubbling of events. This method can be used if bubbles is true

The stopImmediatePropagation() method prevents other event listeners listening to the same event from being called.

If multiple event listeners are attached to the same event type of the same element, when the event is triggered, they are called in the order in which they were added. If you execute stopImmediatePropagation() in one of the event listeners, none of the remaining event listeners will be called.

PreventDefault () cancels the event’s default behavior, such as clicking on a link to jump to. This method can be used if cancelable is true

Type Indicates the type of the event that is triggered

EventPhase Calls the phases of the event handler: 1 for capture, 2 for “in target,” and 3 for bubbling

See Cross-browser Event Objects for more details

<! DOCTYPEhtml>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
    <style>
        .btnCon {
            width: 300px;
            height: 300px;
            border: 1px solid yellow;
        }

        .btn {
            width: 200px;
            height: 200px;
        }

        .btn div {
            width: 100px;
            height: 100px;
            border: 1px solid red;
        }

        .btn div span {
            background-color: #ccc;
        }
    </style>
</head>

<body>
    <div class="btnCon">
        <button class="btn">
            <div>
                <span>button</span>
            </div>
        </button>
    </div>

    <script>
        let btnCon = document.querySelector('.btnCon');
        let btn = document.querySelector('.btnCon div');
        // btn.onclick = c;

        btnCon.addEventListener('click', c);
        btn.addEventListener('click', c);
        // btn.addEventListener('click', c, true);

        function c(event) {
            event = event || wind
            console.log(event );
            // Target of the event
            console.log('Event target =>', event.target);
            // The element of the binding event, pointing to the same as 'this'
            console.log("Elements bound to events =>", event.currentTarget);
            console.log(event.currentTarget === event.target);
            // The type of event that is fired
            console.log("Triggered event type =>",event.type);
            // Call the event handler phase: 0 indicates that no event is being processed at this time, 1 indicates capture phase, 2 indicates "in target", and 3 indicates bubbling phase
            console.log('Stage of calling event handler: 0 means no event is being processed at this time, 1 means capture, 2 means' in target', 3 means bubble ');
            console.log(event.eventPhase);

            // Cancel further capture or bubbling of the event. This method can be used if bubbles is true
            event.stopPropagation();
            // Cancel further capturing or bubbling of events, while preventing any event handlers from being called (new in DOM3 level events)
            event.stopImmediatePropagation();
            // Cancel the event's default behavior, such as clicking on a link to jump to. This method can be used if cancelable is true
            event.preventDefault();
        }
    </script>
</body>

</html>
Copy the code

Stopping events from bubbling/Stopping Propagation

Propagation of events can be interrupted at any stage (capture phase or bubble phase) by calling the stopPropagation method of event objects. After that, the event does not call any listener functions on nodes it passes through later in its propagation.

<input type="button" value="Click Me" id="btn">
<script>
    var btn=document.getElementById("btn");
    btn.onclick = function (event) {
        console.log("Clicked"); / / triggers
        event.stopPropagation();
    }
    document.body.onclick = function (event) {
        console.log("Body clicked"); // Propagation blocking is not triggered
    }
</script>
Copy the code

Calling event.stopPropagation() does not prevent other listener functions of this event from being called on the current node. If you want to prevent other callback function is invoked on the current node, you can use a more radical event. StopImmediatePropagation () method.

Block browser default behavior

Browsers have some default behavior when certain events occur. The most common events are not too link to be clicked. When a click event is fired on a element, it bubbles up to the outermost layer of the DOM structure, document, and the browser interprets the href attribute and loads the contents of the new address in the window.

In Web applications, developers often want to be able to manage navigation information by themselves, rather than by refreshing the page. To do this, we need to override the browser’s default behavior for click events and use our own handling. In this case, we need to call event.preventDefault().

We can block many other default behaviors of browsers. For example, we can prevent scrolling when hitting a space in an HTML5 game, or clicking when text selects a zero box.

Calling Event.stopPropagation () will only prevent subsequent callbacks in the propagation chain from being fired. It doesn’t stop the browser from doing what it does.

<a href="http://www.baidu.com" id="baidu"< p style = "max-width: 100%; clear: both; min-height: 1em;<script>
    document.getElementById('baidu').onclick = function(){
        event.preventDefault();
        console.log('Do a search.');
    }
</script>
Copy the code

Event handler

HTML event handler

<! <input type="button" value=" click Me" onclick="console.log(event.type)"> <! <input type="button" value="Click Me" onclick="console.log(this.value)">Copy the code

Of course event handlers defined in HTML can also call scripts defined elsewhere:

/ / <! -- Chrome output click -->
<script>
    function showMessage(event) {
        console.log(event.type);
    }
</script>
<input type="button" value="Click Me" onclick="showMessage(event)">
Copy the code

Any event handler specified through HTML requires HTML participation, which means that structure and behavior are coupled and not easy to maintain.

DOM0 level event handler

<input type="button" value="Click Me" id="btn">
<script>
    let btn = document.getElementById("btn");
    btn.onclick = function(){
        console.log(this.id); BTN / / output
    }
</script>
Copy the code

Here is a property that assigns a function to an event handler, and event handlers added in this way are processed during the bubbling phase of the event flow. To delete events, set btn.onclick to NULL.

Dom2-level event handler

Dom2-level events define two methods, addEventListener() and removeEventListener(), for adding and removing event handler operations.

All DOM nodes contain these two methods, which take three parameters: the name of the event to process, the function that acts as the event handler, and a Boolean value. The final Boolean argument is true to call the event handler during the capture phase, and false(the default) to call the event handler during the bubble phase.

/ / grammar
btn.addEventListener('click'.function(){}, false);
Copy the code
<input type="button" value="Click Me" id="btn">
<script>
    let btn = document.getElementById("btn");
    btn.addEventListener("click".function(){
        console.log(this.id);
    },false);
    btn.addEventListener("click".function(){
        console.log('Hello word! ');
    },false);
</script>
Copy the code

As you can see from the above example, multiple events can be added to the same DOM element via addEventListener()

The two event handlers in the above code fire in the order they were added, first printing BTN and then Hello Word! .

Event handlers added via addEventListener() can only be removed using removeEventListener(), which passes in the same parameters as when added, i.e. anonymous functions cannot be removed.

<input type="button" value="Click Me" id="btn">
<script>
    let btn=document.getElementById("btn");
    let handler = function(){
        console.log(this.id);
    }
    btn.addEventListener("click", handler, false);
    btn.removeEventListener("click",handler, false);
</script>
Copy the code

IE event handler

IE is usually a maverick, adding and removing event handlers using attachEvent() and detachEvent(), respectively.

**addEventListener()** addEventListener()

  • Add “on” to the event name, such as “onclick”;
  • Without the third Boolean, IE8 and earlier only support event bubbling;
  • Multiple handlers can still be added, but the firing sequence is reversed.

It is also important to note that DOM0 and DOM2 methods are scoped within the element to which they are attached, whereas attachEvent() is global, so if you use this.id as before, instead of accessing the button element, you will get the correct result.

Encapsulate compatible browser event handling

 let EventUtil = {
    addHandler: function (element, type, handler, boolean) {
        if (element.addEventListener) {
            element.addEventListener(type, handler, boolean);
        } 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, boolean);
        } else if (element.detachEvent) {
            element.detachEvent("on" + type, handler);
        } else {
            element["on" + type] = null; }},getEvent: function (event) {
        return event ? event : window.event;
    },
    getTarget: function (event) {
        return event.target || event.srcElement;
    },
    preventDefault: function (event) {
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false; }},stopProgagation: function (event) {
        if (event.stopProgagation) {
            event.stopProgagation();
        } else {
            event.cancelBubble = true; }}};Copy the code

Event delegate/proxy event listener

Event delegates take advantage of event bubbling and manage all events of a certain type by specifying a single event handler. For example, click events bubble all the way up to the Document level (the root element), which means we can specify an onClick event handler for the entire page instead of adding event handlers for each clickable element separately.

Advantages of event delegation

  • It can greatly save memory footprint and reduce event registration
  • You can add a child object without binding it again (dynamically binding events)

Use events to delegate considerations

When you use event delegation, you don’t necessarily want to delegate events as close to the top as possible.

The bubbling process of events also takes time, and the closer you get to the top, the longer the “event propagation chain” of events, the more time it takes.

If the DOM is deeply nested, events bubbling through a large number of ancestor elements can result in a performance penalty.

<ul id="myLinks">
    <li id="goSomewhere">Go somewhere</li>
    <li id="doSomething">Do something</li>
    <li id="sayHi">Say hi</li>
</ul>
<script>
    var list = document.getElementById("myLinks");
    EVentUtil.addHandler (list, "click".function (event) {
        event = EVentUtil.getEvent(event);
        var target = EVentUtil.getTarget(event);

        switch(target.id) {
            case "doSomething":
                document.title = "I changed the document's title";
                break;
            case "goSomewhere":
                location.href = "https://www.baidu.com/";
                break;
            case "sayHi":
                console.log("hi");
                break; }})</script>
Copy the code

The EVentUtil object in the example above, which we encapsulated earlier, can be seen up here

  • As you can see from the example above, we bind events to ul tag id=”myLinks”,
  • And then we can click on a different LI, and the LI will bubble up with the event to trigger the ul bound event,
  • So in the function corresponding to the event,
  • We can then click on a different LI and execute the corresponding code
  • There is no need to bind events to each LI, and later li will also bind events to ul, which is also called dynamic bind events

Remove the event handler

Leaving obsolete “empty event handlers” in memory is also a major cause of memory and performance problems in Web applications.

There are two situations in which these problems may arise:

The first is when an element with an event handler is removed from the document. This can happen through pure DOM manipulation, such as using the removeChild() and replaceChild() methods, but more often happens when you replace a part of the page with innerHTML. If an element with an event handler is removed by innerHTML, the event handler that was added to the element will most likely be garbage collected. Consider the following example:

<div id="myDiv">
    <input type="button" value="ClickMe" id="myBtn">
</div>
<script>
    let btn = document.getElementById("myBtn");
    btn.onclick = function(){
        document.getElementById("myDiv").innerHTML = "Processing...";
    }
</script>
Copy the code

Here, there is a button contained within the

element, which is removed and replaced with a message when clicked to avoid double clicking; This is a very popular practice in web design. The problem is that when a button is removed from the page, it also comes with an event handler. Setting innerHTML in the

element removes the button, but the event handler retains a reference to the button. Some browsers (IE in particular) do not handle this properly and will most likely store references to elements and event handlers in memory. If you want to know that a element is about to be removed, it is best to manually remove the event handler. See the following example:

<div id="myDiv">
    <input type="button" value="ClickMe" id="myBtn">
</div>
<script>
    var btn = document.getElementById("myBtn");
    btn.onclick = function(){
        btn.onclick = null;
        document.getElementById("myDiv").innerHTML="Processing...";
    }
</script>
Copy the code

Here, we remove the button’s event handler before setting the innerHTML attribute of

. This ensures memory can be reused, and removing the button from the DOM is done cleanly.

Note that the delete button in the event handler also prevents the event from bubbling. The target element in the document is the prerequisite for events to bubble up, and only element nodes can bubble up.

Another situation where ** results in “empty event handlers” is when a page is unloaded. ** Not surprisingly, Internet Explorer is still the most problematic browser in this situation, although other browsers have more or less similar problems. If the event handler is not cleaned up before the page is unloaded. Then they’re stuck in memory. Each time the page is loaded and unloaded (either by switching between the two pages or by clicking the “refresh” button), the number of objects stuck in memory increases because the memory occupied by the event handler is not freed.

In general, it is best to remove all event handlers through the OnUnload event handler before the page is unloaded. Here again, the event delegate technique shows its advantage — the fewer events you need to track, the easier it is to remove them. Think of a similar operation like this: Anything added via the OnLoad event handler is eventually removed via the OnUnload event handler.

Some common things to do

The load event:

The load event can be triggered when any resource (including dependent resources) has been loaded. These resources can be images, CSS, scripts, videos, audio files, documents or Windows.

window.onload = function(){}
Copy the code

Load the Image elements:

// window onload
EVentUtil.addHandler (window."load".function () {
    var image = new Image();
    // Specify the event before specifying the SRC attribute
    EVentUtil.addHandler (image, "load".function () {
        console.log("Image loaded!");
    });
    image.src = "smile.gif";
});
Copy the code

Note: New image elements do not have to be added to the document to start the download, as long as the SRC attribute is set.

Script element load:

// window onload
EVentUtil.addHandler (window."load".function () {
    var script = document.createElement("script");
    EVentUtil.addHandler (script, "load".function (event) {
        console.log("loaded!");
    });
    script.src = "example.js";
    document.body.appendChild(script);
})
Copy the code

Unlike images, the js file is not downloaded until the SRC attribute of the script element is set and the element is added to the document

Onbeforeunload Event (HTML5 event) : Listens for page closing events

Window. onbeforeUnload lets developers confirm when they want the user to leave a page. This is useful in some applications, such as when a user accidentally closes a browser TAB. We can ask the user to save his changes and data, or he will lose his action.

EVentUtil.addHandler (window."onbeforeunload".function (event) {
    if(textarea.value ! = textarea.defaultValue) {return 'Do you want to leave the page and discard changes? '; }});Copy the code

It is important to note that adding onbeforeUnload to a page causes the browser to not cache the page, which can affect the access response time of the page. Also, the onbeforeUnload handler must be synchronous.

Resize event: Listens for page size changes

Listening for resize events on window objects is a very common technique in complex reactive layouts. It is difficult to achieve the desired layout through CSS alone. Many times, we need to use JavaScript to calculate and set the size of an element.

Error event:

When our application fails to load resources, we often need to do something about it, especially if the user is on an unstable network. In Financial Times, we used error events to detect some image loading failure inan article and hide it immediately. Since the “DOM Leven 3 Event” specification redefines the error Event to no longer bubble, we can handle the Event in one of two ways.

imageNode.addEventListener('error'.function(event) {
    image.style.display = 'none';
});
Copy the code

Unfortunately, addEventListener does not handle all cases. The only way to ensure that the image-loading error callback is executed is to use the infamous inline Event Handlers.

<img src="http://example.com/image.jpg" onerror="this.style.display='none';" />
Copy the code

The reason is that you can’t be sure that the code that binds the error event handler will be executed before the error event occurs. Using inline handlers means that error listeners are bound when the tag is parsed and the image is requested.

When JavaScript runtime errors (including syntax errors) occur, the window raises an error event from the ErrorEvent interface and executes window.onerror().

Loading a global error event handler can be used to automatically collect error reports.

window.onerror = function(message, source, lineno, colno, error) {... }Copy the code

Function parameters:

  • Message: error message (string). Can be used for events in the HTML onError =”” handler.
  • Source: script URL (string) where the error occurred
  • Lineno: Line number (number) where the error occurred
  • Colno: Column number (digit) where the error occurred
  • Error: Error object (object)

If this function returns true, it prevents execution of the default event handler.

window.addEventListener('error'.function(event) {... })Copy the code

Window. The error details;

References:

Javascript event flow and event delegate;

JS events those things a whole understand;