02 – JavaScript APIs – 02. Advanced events

Advanced events

Register event/bind event

Two ways to register events:

  • traditional way
    1. Use events starting with on. btn.onclick = function() {};
    2.Features: Registration events are unique
    -> Only one handler function can be set for the same event on the same element. The last registered handler function will overwrite the previously registered handler function.
  • Method monitoring
    1.addEventListener()
    2.W3C standards, recommended methods
    3. IE before IE9 does not support this method, you can use attachEvent() instead
    4.Features: Multiple listeners can be registered for the same element and the same event.
    ->The processing functions are executed sequentially in the order of registration

addEventListener() event listening method

  • eventTarget.addEventListener(type, listener[, useCapture])
    1.type: event type string, such as click, here without on
    2.listener: event processing function. When an event occurs, the listening function will be called.
    3.useCapture: Optional parameter, Boolean value, default is false

attachEvent() event monitoring method [supported by IE8 and earlier versions]

  • eventTarget.attachEvent(eventNameWithOn, callback)
    1.eventNameWithOn: event type string, such as onclick, here should bring on
    2.callback: event processing function, the callback function is called when the target triggers the event
    <body>
        <button>Traditional registration event</button>
        <button>Method to listen to registration events</button>
        <button>ie9 attachEvent</button>
        <script>
            var btns = document.querySelectorAll('button');
    
            btns[0].onclick = function() {<!-- -->
                alert('hi');
            }
            btns[0].onclick = function() {<!-- -->
                    alert('hao a u');
    }
    
            btns[1].addEventListener('click', function() {<!-- -->
                alert(22);
            })
            btns[1].addEventListener('click', function() {<!-- -->
                    alert(33);
           })
    // Supported by versions earlier than ie9
            btns[2].attachEvent('onclick', function() {<!-- -->
                alert(11);
            })
        </script>
    </body>
    
    //Compatibility solution
    function addEventListener(element, eventName, fn) {<!-- -->
    if (element.addEventListener) {<!-- -->
     element.addEventListener(eventName, fn);
    } else if (element.attachEvent) {<!-- -->
    element.attachEvent('on' + eventName, fn);
     } else {<!-- -->
     // Equivalent to element.onclick = fn;
     element['on' + eventName] = fn;
    }
    }
    

Delete event/unbind event

Traditional registration method

  • eventTarget.onclick = null;

Method monitoring registration method

  • eventTarget.removeEventListener(type, listener[, useCapture]);[fn call without parentheses]
  • eventTarget.detachEvent(eventNameWithOn, callback);[fn call without parentheses]
    <head>
    <style>
            div {<!-- -->
                width: 100px;
                height: 100px;
                background-color: pink;
            }
        </style>
    </head>
    
    <body>
        <div>1</div>
        <div>2</div>
        <div>3</div>
        <script>
            var divs = document.querySelectorAll('div');
            divs[0].onclick = function() {<!-- -->
                    alert(11);
                    divs[0].onclick = null;
                }
    
            divs[1].addEventListener('click', fn) // fn does not need to be called with parentheses
            function fn() {<!-- -->
                alert(22);
                divs[1].removeEventListener('click', fn);
            }
    
            divs[2].attachEvent('onclick', fn1);
            function fn1() {<!-- -->
                alert(33);
                divs[2].detachEvent('onclick', fn1);
            }
        </script>
    </body>
    
    //Compatibility solution
    function removeEventListener(element, eventName, fn) {<!-- -->
    if (element.removeEventListener) {<!-- -->
     element.removeEventListener(eventName, fn);
     } else if (element.detachEvent) {<!-- -->
     element.detachEvent('on' + eventName, fn);
     } else {<!-- -->
     element['on' + eventName] = null;
    }
    }
    

DOM event flow

  • Event flow: describes the sequence of events received from the page
  • DOM event flow: the process of propagating events among element nodes in a specific order when they occur
  • DOM event flow is divided into 3 stages: capture stage -> current target stage -> bubbling stage

    Note:
    ①Event bubbling: IE was the first to propose it. The event is initially received by the most specific element, and then propagated up to the top node of the DOM.
    ②Event capture: First proposed by Netscape, it starts from the top-level node of the DOM and then propagates downwards step by step to the most specific element reception process.
  • JS code can only perform one of the capturing or bubbling stages
  • addEventListener(type, listener[, useCapture])
    ①useCapture is true, and the event handler is called during the event capture phase;
    ②useCapture is false (if not written, it defaults to false), and the event handler is called in the event bubble stage
  • In actual development, more attention is paid to Event bubbling [Event bubbling sometimes brings trouble, sometimes brings ingenuity]
  • onclick, attachEvent can only get the bubbling stage
  • onblur, onfocus, onmouseenter, onmouseleave can only get the capture phase
  • Example
    <head>
        <style>
            .father {<!-- -->
                overflow: hidden;
                width: 300px;
                height: 300px;
                margin: 100px auto;
                background-color: pink;
                text-align: center;
            }
            .son {<!-- -->
                width: 200px;
                height: 200px;
                margin: 50px;
                background-color: purple;
                line-height: 200px;
                color: #fff;
            }
        </style>
    </head>
    
    <body>
        <div class="father">
            <div class="son">son box</div>
        </div>
        <script>
            // var son = document.querySelector('.son');
            // son.addEventListener('click', function() { // father -> son
            // alert('son');
            // }, true);
            // var father = document.querySelector('.father');
            // father.addEventListener('click', function() {<!-- -->
            // alert('father');
            // }, true);
            
            document.addEventListener('click', function() {<!-- --> // son -> father -> document
                alert('document');
            })
            var father = document.querySelector('.father');
            father.addEventListener('click', function() {<!-- -->
                alert('father');
            }, false);
            var son = document.querySelector('.son');
            son.addEventListener('click', function() {<!-- -->
                alert('son');
            }, false);
        </script>
    </body>
    

Event Object

Overview

  • eventTarget.onclick = function(event) {}
    eventTarget.addEventListener('click', function(event) {})
    event represents the status of the event, such as the status of keyboard keys, mouse button status, and mouse position. That is, after an event occurs, a collection of information data related to the event. Event has many attributes and methods.

Applicable syntax

  • eventTarget.onclick = function(event) {}[event can be written as e or evt][event does not need to pass actual parameters, the system helps us set it as an event object. When registering an event, the event will be automatically created by the system and passed to the event listener in turn]
  • eventTarget.addEventListener('click', function(event) {})[event can be written as e or evt][event does not need to pass actual parameters, the system helps us set it as an event object. When registering an event, the event will be automatically created by the system and passed to the event listener in turn]
  • Example:
    <head>
        <style>
            div {<!-- -->
                width: 100px;
                height: 100px;
                background-color: pink;
            }
        </style>
    </head>
    
    <body>
        <div>123</div>
        <script>
            var div = document.querySelector('div');
            div.onclick = function(e) {<!-- -->
           e = e || window.event;
       console.log(e);
    }
         div.addEventListener('click', function(e) {<!-- -->
      console.log(e);
            })
        </script>
    </body>
    

Compatibility Plan

  • There are compatibility issues in obtaining the event object itself:
    1. In standard browsers, the parameters passed by the browser to the method can be obtained by simply defining the formal parameter e.
    2. In IE6~8, the browser will not pass parameters to the method. If necessary, you have to go to window.event to get the search
  • Solution: e = e || window.event [see applicable syntax examples]

Common properties and methods

  • e.type[Return the type of event, such as click, without on]
  • e.target[Return the object that triggered the event][Standard]
    currentTarget [Similar to e.target] [ie678 does not recognize it]
    this[Returns the object of the bound event, that is, the caller of the function]
    <body>
        <div>123</div>
        <ul>
            <li>abc</li>
            <li>abc</li>
            <li>abc</li>
        </ul>
    <script>
            var ul = document.querySelector('ul');
            ul.addEventListener('click', function(e) {<!-- -->
      console.log(this); // points to ul
    console.log(e.currentTarget);
                console.log(e.target); // If the click is li, then e.target points to li
    })
            
            // Understand compatibility
            // div.onclick = function(e) {<!-- -->
            // e = e || window.event;
            // var target = e.target || e.srcElement;
            // console.log(target);
            // }
        </script>
    </body>
    
  • e.srcElement[Return the object that triggered the event][Non-standard, used by ie6-8]
  • e.stopPropagation()[Prevent bubbling][Standard]
  • e.cancelBubble[Prevent bubbling][Non-standard, used by ie6-8]
  • e.preventDefault()[Prevent default event][Standard]
  • e.returnValue[Block default events][Non-standard, used by ie6-8, such as prohibiting link jumps]

Prevent events from bubbling

Two ways

  • e.stopPropagation()[Standard]
  • e.cancelBubble = true;[Non-standard]
  • Example
    <body>
        <div>123</div>
        <a href="http://www.baidu.com">Baidu</a>
        <form action="http://www.baidu.com">
        <input type="submit" value="Submit" name="sub">
        </form>
        <script>
            var div = document.querySelector('div');
            div.addEventListener('click', fn);
            div.addEventListener('mouseover', fn);
            div.addEventListener('mouseout', fn);
    
            function fn(e) {<!-- -->
                console.log(e.type);
            }
    
            var a = document.querySelector('a');
            a.addEventListener('click', function(e) {<!-- -->
                    e.preventDefault();
            })
    
            a.onclick = function(e) {<!-- -->
                // Ordinary browser e.preventDefault(); method
                // e.preventDefault();
                
                // Lower version browser ie678 returnValue attribute
                // e.returnValue;
                
                // Return false can also be used to prevent the default behavior
                // No compatibility issues
                // Features: The code after return will not be executed and is limited to traditional registration methods.
                return false;
                alert(11);
            }
        </script>
    </body>
    
    //Compatibility solution
    if(e & amp; & amp; e.stopPropagation){<!-- -->
    e.stopPropagation();
    }else{<!-- -->
    window.event.cancelBubble = true;
    }
    
    //Prevent bubbling
    <head>
        <style>
            .father {<!-- -->
                overflow: hidden;
                width: 300px;
                height: 300px;
                margin: 100px auto;
                background-color: pink;
                text-align: center;
            }
            .son {<!-- -->
                width: 200px;
                height: 200px;
                margin: 50px;
                background-color: purple;
                line-height: 200px;
                color: #fff;
            }
        </style>
    </head>
    
    <body>
        <div class="father">
            <div class="son">son son</div>
        </div>
        <script>
            var son = document.querySelector('.son');
            son.addEventListener('click', function(e) {<!-- -->
                alert('son');
                e.stopPropagation();
                e.cancelBubble = true;
            }, false);
    
            var father = document.querySelector('.father');
            father.addEventListener('click', function() {<!-- --> // father is not blocked
                alert('father');
            }, false);
            
            document.addEventListener('click', function() {<!-- -->
                alert('document');
            })
        </script>
    </body>
    

Event delegation (agency, delegation)

Event delegation/event proxy [called event delegation in jQuery]

  • Instead of setting event listeners individually for each child node, the event listener is set on its parent node and then uses the bubbling principle to affect the setting of each child node.
    For example, register a click event for ul, and then use the target of the event object to find the currently clicked li. Because when li is clicked, the event will bubble up to ul. If ul has a registered event, the event listener will be triggered.
  • Only operates the DOM once, improving the performance of the program
  • Example
    <body>
        <ul>
            <li>Do you know if you know it? If you click on it, you should have the pop-up box in hand!</li>
            <li>Do you know if you know it? If you click on it, you should have the pop-up box in hand!</li>
            <li>Do you know if you know it? If you click on it, you should have the pop-up box in hand!</li>
            <li>Do you know if you know it? If you click on it, you should have the pop-up box in hand!</li>
            <li>Do you know if you know it? If you click on it, you should have the pop-up box in hand!</li>
        </ul>
        <script>
            var ul = document.querySelector('ul');
            ul.addEventListener('click', function(e) {<!-- -->
                e.target.style.backgroundColor = 'pink';
            })
        </script>
    </body>
    

Commonly used mouse events

  • onclick, onmouseover, onmouseout, onfocus, onblur, onmousemove, onmouseup, onmousedown
  • contextmenu[Disable right-click menu], selectstart[Disable mouse selection]
    <body>
        I am a text that I don’t want to share
        <script>
            document.addEventListener('contextmenu', function(e) {<!-- --> // Disable right-click menu
                    e.preventDefault();
            })
            document.addEventListener('selectstart', function(e) {<!-- --> // Disable text selection
                e.preventDefault();
            })
        </script>
    </body>
    
  • e.clientX, e.clientY [Returns the XY coordinates of the mouse relative to the visible area of the browser window]
    e.pageX, e.pageY [Returns the XY coordinates of the mouse relative to the document page] [IE9 + supported]
    e.screenX, e.screenY[Returns the XY coordinates of the mouse relative to the computer screen]
    <head>
        <style>
            body {<!-- -->
                height: 3000px;
            }
        </style>
    </head>
    
    <body>
        <script>
            document.addEventListener('click', function(e) {<!-- -->
                console.log(e.clientX);
                console.log(e.clientY);
                console.log('--------------------------');
    
                console.log(e.pageX);
                console.log(e.pageY);
                console.log('--------------------------');
    
                console.log(e.screenX);
                console.log(e.screenY);
            })
        </script>
    </body>
    
  • Example
    //Angel following the mouse
    <head>
        <style>
            img {<!-- -->
                position: absolute; // The picture needs to be moved a certain distance without occupying the position. Just use absolute positioning.
                top: 2px;
            }
        </style>
    </head>
    
    <body>
        <img src="images/angel.gif" alt="">
        <script>
            var pic = document.querySelector('img');
            document.addEventListener('mousemove', function(e) {<!-- -->
                var x = e.pageX;
                var y = e.pageY;
                console.log('x coordinate is' + x, 'y coordinate is' + y);
                
                pic.style.left = x - 50 + 'px'; // Be sure to add px units
                pic.style.top = y - 40 + 'px';
            });
        </script>
    </body>
    

Commonly used keyboard events

  • onkeyup[Triggered when a keyboard key is released][Not sensitive to uppercase and lowercase letters]
  • onkeydown[Triggered when a keyboard key is pressed][Not sensitive to uppercase and lowercase letters]
  • onkeypress [Triggered when a keyboard key is pressed] [Function keys cannot be recognized, such as ctrl, shift, arrow] [Case-sensitive letters]
    The execution order of the three: keydown -> keypress -> keyup
    <body>
        <script>
          document.onkeyup = function() {<!-- -->
            console.log('I played');
    }
    
            document.addEventListener('keypress', function() {<!-- -->
            console.log('I pressed press');
            })
    
            document.addEventListener('keydown', function() {<!-- -->
            console.log('I pressed down');
            })
        </script>
    </body>
    
  • keyCode[Returns the ASCII value of the key][Case-sensitive letters]
    <body>
        <script>
            document.addEventListener('keyup', function(e) {<!-- -->
                // console.log(e);
                console.log('up:' + e.keyCode);
                if (e.keyCode === 65) {<!-- -->
                    alert('The a key you pressed');
                } else {<!-- -->
                    alert('You did not press the a key')
                }
            })
            document.addEventListener('keypress', function(e) {<!-- -->
                // console.log(e);
                console.log('press:' + e.keyCode);
            })
        </script>
    </body>
    
  • Example
    //Simulate JD key input content
    <body>
        <input type="text">
        <script>
            var search = document.querySelector('input');
            // When the keydown and keypress events are triggered, the text has not yet fallen into the text box.
            // When the keyup event is triggered, the text has fallen into the text box
            document.addEventListener('keyup', function(e) {<!-- --> // If it is keydown, s will also be entered when getting focus
                if (e.keyCode === 83) {<!-- -->
                    search.focus();
                }
            })
        </script>
    </body>
    
    // Simulate JD express tracking number query
    <head>
        <style>
            * {<!-- -->
                margin: 0;
                padding: 0;
            }
            .search {<!-- -->
                position: relative;
                width: 178px;
                margin: 100px;
            }
            .con {<!-- -->
                display: none;
                position: absolute;
                top: -40px;
                width: 171px;
                border: 1px solid rgba(0, 0, 0, .2);
                box-shadow: 0 2px 4px rgba(0, 0, 0, .2);
                padding: 5px 0;
                font-size: 18px;
                line-height: 20px;
                color: #333;
            }
            .con::before {<!-- -->
                content: '';
                width: 0;
                height: 0;
                position: absolute;
                top: 28px;
                left: 18px;
                border: 8px solid #000;
                border-style: solid dashed dashed;
                border-color: #fff transparent transparent;
            }
        </style>
    </head>
    
    <body>
        <div class="search">
            <div class="con">123</div>
            <input type="text" placeholder="Please enter your courier number" class="jd">
        </div>
        <script>
            var con = document.querySelector('.con');
            var jd_input = document.querySelector('.jd');
            jd_input.addEventListener('keyup', function() {<!-- -->
            if (this.value == '') {<!-- -->
                con.style.display = 'none';
             } else {<!-- -->
                  con.style.display = 'block';
                 con.innerText = this.value;
            }
        })
    
            jd_input.addEventListener('blur', function() {<!-- -->
            con.style.display = 'none';
            })
            jd_input.addEventListener('focus', function() {<!-- -->
                if (this.value !== '') {<!-- -->
                con.style.display = 'block';
                }
            })
        </script>
    </body>