• 深入理解DOM事件机制系列第三篇——事件对象


    前面的话

      在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息。所有浏览器都支持event对象,但支持方式不同。本文将详细介绍事件对象

    获取事件对象

      【1】一般地,event对象是事件程序的第一个参数

      [注意]IE8-浏览器不支持

    //IE8-浏览器输出undefined,其他浏览器则输出事件对象[object MouseEvent]
    <div id="box" style="height:30px;200px;background:pink;"></div>
    <script>
    var oBox = document.getElementById('box');
    oBox.onclick = function(a){
        box.innerHTML = a;
    }
    </script>

      【2】另一种方法是直接使用event变量

      [注意]firefox浏览器不支持

    //firefox浏览器输出undefined,其他浏览器则输出事件对象[object MouseEvent]  
    <div id="box" style="height:30px;200px;background:pink;"></div>
    <script>
    var oBox = document.getElementById('box');
    oBox.onclick = function(){
        box.innerHTML = event;
    }
    </script>

    兼容

      于是,对于获取事件对象的常见兼容写法如下

    <div id="box" style="height:30px;200px;background:pink;"></div>
    <script>
    var oBox = document.getElementById('box');
    oBox.onclick = function(e){
        e = e || event;
        box.innerHTML = e;
    }
    </script>

    属性和方法

      事件对象包含与创建它的特定事件有关的属性和方法。触发的事件类型不一样,可用的属性和方法也不一样。不过,所有事件都有些共有的属性和方法

    事件类型

      事件有很多类型,事件对象中的type属性表示被触发的事件类型

    <div id="box" style="height:30px;200px;background:pink;"></div>
    <script>
    //鼠标移入时,显示mouseover;移出时,显示mouseout;点击时,显示click
    var oBox = document.getElementById('box');
    oBox.onclick = oBox.onmouseout =oBox.onmouseover =function(e){
        e = e || event;
        box.innerHTML = e.type;
    }
    </script>

      通过点击或按tab键将焦点切换到button按钮上可以触发focus事件

    <button id="box" style="height:30px;200px;background:pink;"></button>
    <script>
    var oBox = document.getElementById('box');
    oBox.onfocus = function(e){
        e = e || event;
        box.innerHTML = e.type;
    }
    </script>

    事件目标

      关于事件目标,共有currentTarget、target和srcElement这三个属性

    currentTarget

      currentTarget属性返回事件当前所在的节点,即正在执行的监听函数所绑定的那个节点

      [注意]IE8-浏览器不支持

      一般地,currentTarget与事件中的this指向相同。但在attachEvent()事件处理程序中,this指向window,详细信息移步至此

    <style>
    .in{height: 30px;background-color: lightblue;margin:0 10px;}
    </style>
    <ul id="box">
        <li class="in">1</li>
        <li class="in">2</li>
    </ul>
    <script>
    box.onclick = function(e){
        e = e || event;
        var tags =  box.getElementsByTagName('li');
        tags[0].innerHTML = e.currentTarget;
        tags[1].innerHTML = (e.currentTarget === this);
    }
    </script>

    target

      currentTarget属性返回事件正在执行的监听函数所绑定的节点,而target属性返回事件的实际目标节点

      [注意]IE8-浏览器不支持

      以下代码中,点击该实际目标节点时,颜色变品红;移出时,颜色变浅蓝

    <style>
    #box{background-color: lightblue;}
    .in{height: 30px;}
    </style>
    <ul id="box">
        <li class="in">1</li>
        <li class="in">2</li>
    </ul>
    <script>
    box.onclick = function(e){
        e = e || event;
        e.target.style.backgroundColor = 'pink';
    }
    box.onmouseout = function(e){
        e = e || event;
        e.target.style.backgroundColor = 'lightblue';
    }
    </script>

    srcElement

      srcElement属性与target属性功能一致

      [注意]firefox浏览器不支持

    <style>
    #box{background-color: lightblue;}
    .in{height: 30px;}
    </style>
    <ul id="box">
        <li class="in">1</li>
        <li class="in">2</li>
    </ul>
    <script>
    box.onclick = function(e){
        e = e || event;
        e.srcElement.style.backgroundColor = 'pink';
    }
    box.onmouseout = function(e){
        e = e || event;
        e.srcElement.style.backgroundColor = 'lightblue';
    }
    </script>

    兼容 

    var handler = function(e){
        e = e || event;
        var target = e.target || e.srcElement;
    }

    事件代理

      由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(delegation),也叫事件委托

      事件代理应用事件目标的target和srcElement属性完成。利用事件代理,可以提高性能及降低代码复杂度

      有一个需求,一个<ul>中有5个<li>,移入时变浅蓝,移出时变品红

      下面分别用常规方法和事件代理方法来实现

    <style>
    #box{background-color: pink;}
    .in{height: 30px;}
    </style>
    <ul id="box">
        <li class="in">1</li>
        <li class="in">2</li>
        <li class="in">3</li>
        <li class="in">4</li>
        <li class="in">5</li>
    </ul>
    <script>
    //常规方法
    var tags = box.getElementsByTagName('li');
    for(var i = 0; i < tags.length; i++){
        tags[i].onmouseover = function(e){
            this.style.backgroundColor = 'lightblue';
        }
        tags[i].onmouseout = function(e){
            this.style.backgroundColor = 'pink';
        }
    }
    </script>
    
    <script>
    //事件代理方法
    box.onmouseover = function(e){
        e = e || event;
        var target = e.target || e.srcElement;
        target.style.backgroundColor = 'lightblue';
    }
    box.onmouseout = function(e){
        e = e || event;
        var target = e.target || e.srcElement;
        target.style.backgroundColor = 'pink';
    }
    </script>

      如果可行的话,也可以考虑为document添加一个事件处理程序,用以处理页面上发生的某种特定类型的事件。这样做与采取传统的做法相比有以下优点:

      1、document对象很快就可以访问,而且可以在页面生命周期的任何时间点上为它添加事件处理程序,而无需等待DOMContentLoadedload事件。换句话说,只要可单击的元素呈现在页面上,就可以立即具备适当的功能

      2、在页面中设置事件处理程序所需的时间更少。只添加一个事件处理程序所需的DOM引用更少,所花的时间也更少

      3、整个页面占用的内存空间更少,能够提升整体性能

      最适合使用事件委托技术的事件包括click、mousedown、mouseup、keydown、keyup和keypress

      下面封装一个可以使用事件委托的事件绑定函数

    function bindEvent(elem,type,selector,fn){
      if(fn == null){
        fn = selector;
        selector = null;
      }
      elem.addEventListener(type,function(e){
        var target;
        if(selector){
          target = e.target;
          if(target.matches(selector)){
            fn.call(target,e);
          }
        }else{
          fn(e);
        }
      })
    }

    事件冒泡

      事件冒泡是事件流的第三个阶段,通过事件冒泡可以在这个阶段对事件做出响应

      关于冒泡,事件对象中包含bubbles、cancelBubble、stopPropagation()和stopImmediatePropagation()这四个相关的属性和方法

    bubbles

      bubbles属性返回一个布尔值,表示当前事件是否会冒泡。该属性为只读属性

      发生在文档元素上的大部分事件都会冒泡,但focus、blur和scroll事件不会冒泡。所以,除了这三个事件bubbles属性返回false外,其他事件该属性都为true

    <button id="test" style="height: 30px; 200px;"></button>
    <script>
    //点击按钮时,按钮内容为true,说明click事件默认可冒泡
    test.onclick = function(e){
        test.innerHTML =e.bubbles;//true
    }
    </script>

    <div id="test" style="height: 50px; 200px;overflow:scroll;background:pink;line-height:60px;">内容</div>
    <script>
    //滚动时,div内容变成false,说明scroll事件默认不可冒泡
    test.onscroll = function(e){
        test.innerHTML =e.bubbles;//false
    }
    </script>

    stopPropagation()

      stopPropagation()方法表示取消事件的进一步捕获或冒泡,无返回值

      [注意]IE8-浏览器不支持

    <button id="test" style="height: 30px; 200px;"></button>
    <script>
    //点击按钮时,按钮内容为'button',因为阻止了<button>向<body>的冒泡
    test.onclick = function(e){
        e = e || event;
        e.stopPropagation();
        test.innerHTML +='button
    ';
    }
    document.body.onclick = function(e){
        test.innerHTML += 'body
    '
    }
    </script>

    stopImmediatePropagation()

      stopImmediatePropagation()方法不仅可以取消事件的进一步捕获或冒泡,而且可以阻止同一个事件的其他监听函数被调用,无返回值

      [注意]IE8-浏览器不支持

      使用stopIPropagation()方法,可以阻止冒泡,但无法阻止同一事件的其他监听函数被调用

    <button id="test" style="height: 30px; 200px;"></button>
    <script>
    //使用stopIPropagation()方法,<button>内部变为'button',且背景颜色变成浅蓝
    test.addEventListener('click',function(e){
        e = e || event;
        e.stopPropagation();
        test.innerHTML +='button
    ';    
    })
    test.addEventListener('click',function(e){
        e = e || event;
        test.style.background = 'lightblue';    
    })
    document.body.onclick = function(e){
        test.innerHTML += 'body
    '
    }
    </script>

      使用stopImmediatePropagation()方法,即可以阻止冒泡,也可以阻止同一事件的其他监听函数被调用

    <button id="test" style="height: 30px; 200px;"></button>
    <script>
    //使用stopImmediatePropagation()方法,<button>内部变为'button',且背景颜色不变
    test.addEventListener('click',function(e){
        e = e || event;
        e.stopImmediatePropagation();
        test.innerHTML +='button
    ';    
    })
    test.addEventListener('click',function(e){
        e = e || event;
        test.style.background = 'lightblue';    
    })
    document.body.onclick = function(e){
        test.innerHTML += 'body
    '
    }
    </script>

    cancelBubble

      cancelBubble属性只能用于阻止冒泡,无法阻止捕获阶段。该值可读写,默认值是false。当设置为true时,cancelBubble可以取消事件冒泡

      [注意]该属性全浏览器支持,但并不是标准写法

    <button id="test" style="height: 30px; 200px;"></button>
    <script>
    test.onclick = function(e){
        e = e || event;
        e.cancelBubble = true;
        test.innerHTML +='button
    ';
    }
    document.body.onclick = function(e){
        test.innerHTML += 'body
    '
    }
    </script>

      当使用stopIPropagation()方法或stopImmediatePropagation()方法时,关于cancelBubble值的变化,各浏览器表现不同

    //chrome/safari/opera中,cancelBubble的值为false
    //IE9+/firefox中,cancelBubble的值为true
    <button id="test" style="height: 30px; 200px;"></button>
    <script>
    test.onclick = function(e){
        e = e || event;
        e.stopPropagation();
        test.innerHTML = e.cancelBubble;
    }
    </script>    

    兼容

    var handler = function(e){
        e = e || event;
        if(e.stopPropagation){
            e.stopPropagation();
        }else{
            e.cancelBubble = true;
        }
    }

    事件流

    eventPhase

      eventPhase属性返回一个整数值,表示事件目前所处的事件流阶段

      0表示事件没有发生,1表示捕获阶段,2表示目标阶段,3表示冒泡阶段

      [注意]IE8-浏览器不支持

    【1】以下代码返回2,表示处于目标阶段

    <button id="test" style="height: 30px; 200px;"></button>
    <script>
    test.onclick = function(e){
        e = e || event;
        test.innerHTML = e.eventPhase;
    }
    </script>

    【2】以下代码返回1,表示处于捕获阶段

    <button id="test" style="height: 30px; 200px;"></button>
    <script>
    document.addEventListener('click',function(e){
        e = e || event;
        test.innerHTML = e.eventPhase;
    },true);
    </script>

    【3】以下代码返回3,表示处于冒泡阶段

    <button id="test" style="height: 30px; 200px;"></button>
    <script>
    document.addEventListener('click',function(e){
        e = e || event;
        test.innerHTML = e.eventPhase;
    },false);
    </script>

    取消默认行为

      常见的默认行为有点击链接后,浏览器跳转到指定页面;或者按一下空格键,页面向下滚动一段距离

      关于取消默认行为的属性包括cancelable、defaultPrevented、preventDefault()和returnValue

    使用

      1、在DOM0级事件处理程序中取消默认行为,使用returnValue、preventDefault()和return false都有效

      2、在DOM2级事件处理程序中取消默认行为,使用return false无效

      3、在IE事件处理程序中取消默认行为,使用preventDefault()无效

      点击下列锚点时,会自动打开博客园首页

    <a id="test" href="http://www.cnblogs.com" target="_blank">链接</a>

    cancelable

      cancelable属性返回一个布尔值,表示事件是否可以取消。该属性为只读属性。返回true时,表示可以取消。否则,表示不可取消

      [注意]IE8-浏览器不支持

    <a id="test" href="#">链接</a>
    <script>
    test.onclick= function(e){
        e = e || event;
        test.innerHTML = e.cancelable;
    }
    </script>

    preventDefault()

      preventDefault()方法取消浏览器对当前事件的默认行为,无返回值

      [注意]IE8-浏览器不支持

    <a id="test" href="http://www.cnblogs.com">链接</a>
    <script>
    test.onclick= function(e){
        e = e || event;
        e.preventDefault();
    }
    </script>

    returnValue

      returnValue属性可读写,默认值是true,但将其设置为false就可以取消事件的默认行为,与preventDefault()方法的作用相同

      [注意]firefox和IE9+浏览器不支持

    <a id="test" href="http://www.cnblogs.com">链接</a>
    <script>
    test.onclick= function(e){
        e = e || event;
        e.returnValue = false;
    }
    </script>

    兼容

    var handler = function(e){
        e = e || event;
        if(e.preventDefault){
            e.preventDefault();
        }else{
            e.returnValue = false;
        }
    }

    return false

      除了以上方法外,取消默认事件还可以使用return false

    <a id="test" href="http://www.cnblogs.com">链接</a>
    <script>
    test.onclick= function(e){
        return false;
    }
    </script>

    defaultPrevented

      defaultPrevented属性表示默认行为是否被阻止,返回true时表示被阻止,返回false时,表示未被阻止

      [注意]IE8-浏览器不支持

    <a id="test" href="http://www.cnblogs.com">链接</a>
    <script>
    test.onclick= function(e){
        e = e || event;
        if(e.preventDefault){
            e.preventDefault();
        }else{
            e.returnValue = false;
        }
        test.innerHTML = e.defaultPrevented;
    }
    </script>

  • 相关阅读:
    vs整合MySQL和QT
    VS2019中QT连接及使用
    JavaScript 进阶入门
    解决MySQL workbench的resultgird不出现的问题
    JavaScript入门
    CSS学习
    Linux下如何查看tomcat是否启动、查看tomcat启动日志
    oracle常见的函数
    java.lang.ClassNotFoundException: org.springframework.web.filter.CharacterEncodingFilter
    位运算(&、|、^、~、>>、<<)
  • 原文地址:https://www.cnblogs.com/xiaohuochai/p/5862775.html
Copyright © 2020-2023  润新知