• 深入理解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>

  • 相关阅读:
    Median Value
    237. Delete Node in a Linked List
    206. Reverse Linked List
    160. Intersection of Two Linked Lists
    83. Remove Duplicates from Sorted List
    21. Merge Two Sorted Lists
    477. Total Hamming Distance
    421. Maximum XOR of Two Numbers in an Array
    397. Integer Replacement
    318. Maximum Product of Word Lengths
  • 原文地址:https://www.cnblogs.com/xiaohuochai/p/5862775.html
Copyright © 2020-2023  润新知