• js事件浅析


    js中关于DOM的操作很多,因此js事件机制也就尤为重要。

    事件绑定形式:

    一. 内联形式

    耦合度高,不利于维护

    <button onclick="alert('你点击了这个按钮');">点击这个按钮</button>

    二. 属性绑定(DOM0级事件)

    只能绑定一个函数

    button.onclick = function() {};

    三. 事件监听函数(DOM2级事件)

    element.addEventListener(<event-name>, <callback>, <use-capture>);

    element.removeEventListener(<event-name>, <callback>, <use-capture>);

    element.attachEvent(event, callback)(IE11以后用addEventLisener);

    element.detachEvent(event, callback)(IE11以后用addEventLisener);

    事件代理

    在父元素上绑定事件,监听子元素的事件。主要用于子元素是新建元素或者子元素个数很多的情况下。这种方法可以提高性能,同时避免提前绑定元素事件而导致新建元素的事件没有生效的结果。

    <ul> <li>11111111111111111111</li> </ul>

    document.addEventListener('click', function (e) {
                console.log('document currentTarget: ' + e.currentTarget.nodeName);
                console.log('document target: ' + e.target.nodeName);
                if (e.target.nodeName === 'LI') {
                    console.log('dom delegate: ' + e.eventPhase);
                }
    
                console.log(this);
            }, true);

     

    事件触发顺序

    • Event Capturing(事件捕获): Netscape
    • Event Bubbling(事件冒泡): IE

    这两种方式确定了事件执行的前后顺序,只不过后来W3C对DOM2的事件模型给出了一个规范:首先进入事件捕获阶段->达到元素后->进入事件冒泡阶段。

    可以通过event.eventPhase查看事件触发阶段:

    eventPhase (number): 这个属性的数字表示当前事件触发在什么阶段。

    • 0: none
    • 1: 捕获
    • 2: 目标
    • 3: 冒泡

    1. DOM0

    在元素处于目标时触发该事件。

    2. DOM2
    当addEventListener的最后参数为false时,是在冒泡阶段触发。如果是true的话是在捕获阶段出发。attachEvent始终是冒泡阶段触发。

    允许捕获机制的事件流触发顺序:

    事件流的触发顺序是首先从document元素开始,触发绑定在document上的捕获事件,依次向下,直到目标元素上。然后触发绑定在目标元素上的事件。最后依次向上,直到触发document元素上绑定的捕获事件。分别可以对于捕获阶段,处于目标阶段,冒泡阶段,捕获过程和冒泡过程并不包含目标元素阶段。

    image

    尝试下面的函数:

    <ul>
            <li>11111111111111111111</li>
    </ul>
    <script>
        document.querySelector('li').addEventListener('click', function (e) {
                console.log('False currentTarget: ' + e.currentTarget.nodeName);
                console.log('False target: ' + e.target.nodeName);
                console.log(e.eventPhase);
                console.log(this);
            }, false);
        document.querySelector('li').addEventListener('click', function (e) {
                console.log('True currentTarget: ' + e.currentTarget.nodeName);
                console.log('True target: ' + e.target.nodeName);
                console.log(e.eventPhase);
                console.log(this);
            }, true);
    
        document.querySelector('ul').addEventListener('click', function (e) {
                console.log('ul false currentTarget: ' + e.currentTarget.nodeName);
                console.log('ul false target: ' + e.target.nodeName);
                console.log(e.eventPhase);
                console.log(this);
            }, false);
        document.querySelector('ul').addEventListener('click', function (e) {
                console.log('ul true currentTarget: ' + e.currentTarget.nodeName);
                console.log('ul true target: ' + e.target.nodeName);
                console.log(e.eventPhase);
                console.log(this);
            }, true);
        document.querySelector('li').onclick = function (e) {
                console.log('Onclick currentTarget: ' + e.currentTarget.nodeName);
                console.log('Onclick target: ' + e.target.nodeName);
                console.log(e.eventPhase);
                console.log(this);
            };
    
    </script>

    BeCareful: 可以看到,当点击li的时候,前两个绑定的事件是按照顺序来执行的,并没有先执行捕获事件然后执行冒泡事件,而是按照绑定顺序执行的。且event.eventPhase的值为2。

    原因是:浏览器针对于事件的触发机制是,执行每个阶段会先设置在哪个阶段,然后在node的事件数组里执行相应阶段的事件。如果处于目标阶段是不区分捕获或者冒泡阶段的,直接按照注册顺序执行当前事件数组里的函数。event.eventPhase是在调用这些方法的时候设置的。而true和false是在注册的时候开发者传入的。

    11222334482834565

    注释里面的那段话的意思就是,在目标阶段会触发捕获和冒泡事件的监听函数,因此,它会按照注册顺序执行,跟我们平时理解的顺序并不一样。

    169109115492551665

    600955579212067002

    自定义事件

    DOM3级还定义了自定义事件,自定义事件不是由DOM原生触发的,它的目的是让开发人员创建自己的事件。要创建的自定义事件可以由createEvent("CustomEvent");
    返回的对象有一个initCustomEvent()方法接收如下四个参数。
    1)type:字符串,触发的事件类型,自定义。例如 “keyDown”,“selectedChange”;
    2)bubble(布尔值):标示事件是否应该冒泡;
    3)cancelable(布尔值):标示事件是否可以取消;
    4)detail(对象):任意值,保存在event对象的detail属性中;
    可以像分配其他事件一样在DOM中分派创建的自定义事件对象。如:

    var  div = document.getElementById("myDiv");
    EventUtil.addEventHandler(div,"myEvent", function () {
    alert("div myEvent!");
    });
    EventUtil.addEventHandler(document,"myEvent",function(){
    alert("document myEvent!");
    });
    if(document.implementation.hasFeature("CustomEvents","3.0")){
    var e = document.createEvent("CustomEvent");
    e.initCustomEvent("myEvent",true,false,"hello world!");
    div.dispatchEvent(e);
    }

    事件对象及行为

    1. 事件目标

    event = event || window.event;
    target = event.target || event.srcElement;

    event.target 和event.currentTarget的区别:前者是触发事件的最终目标,后者是绑定事件时的目标。

    借用事件代理的例子:

    <div class="btn" onclick="console.log('onclick')">
            <span>sss</span>
    </div>

    
    document.querySelector('.btn').addEventListener('click', function (e) {
                console.log('False currentTarget: ' + e.currentTarget.nodeName);
                console.log('False target: ' + e.target.nodeName);
                console.log(e.eventPhase);
                console.log(this);
            }, false);

    image

    2. 取消默认行为 & 阻止事件冒泡

    DOM:
    event.preventDefault(); 
    event.stopPropagation();
    IE8以下:
    event.returnValue = false;
    event.cancelBubble = true;

    return false方式:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <script src="http://cdn.bootcss.com/jquery/1.11.0/jquery.js"></script>
    </head>
    <body>
    
        <div onclick="alert('Outer clicked')">
            Outer Div<br><br>
            <a id="inner" href="http://www.google.com" onclick="return false;">Google</a>
        <script>
            document.getElementById('inner').addEventListener('click', function(e){
                alert(e.type);
                e.stopPropagation();
                return false;
            }, false);
            document.getElementById('inner').onclick = function(e){
                alert(e.type);
                e.stopPropagation();
                return false;
            };
    
            $('#inner').click(function (e) {
                return false;
            });
        </script>
    </div>
    </body>
    </html>

    在没有使用jquery的情况下,return false这种方式只有在DOM0的方式时可以相当于阻止默认行为的方法,DOM2级事件是不起任何效果的。

    如果在jquery环境,return false相当于阻止默认行为和冒泡行为的方法,因为jquery本身的定义。

    参考资料:

    1. 前端工程师手册

  • 相关阅读:
    MQ、JMS以及ActiveMQ 关系的理解
    java对象 深度克隆(不实现Cloneable接口)和浅度克隆
    crontab 各参数详解及如何查看日志记录
    mybatis xml 文件中like模糊查询
    jexl2 执行字符串Java代码
    java代码执行字符串中的逻辑运算方法
    mybatis 传入多个参数
    mybatis通用mapper源码解析(二)
    mybatis通用mapper源码解析(一)
    mybatise插件反向生成数据库表相关Java代码
  • 原文地址:https://www.cnblogs.com/Candybunny/p/5592096.html
Copyright © 2020-2023  润新知