dom事件机制系列

JS事件流机制

  一个完整的JS事件流是从window开始,最后回到window的一个过程,事件流被分为三个阶段:

  (1~5)捕获过程、(5~6)目标过程、(6~10)冒泡过程。

  通过addEventListener可以监听冒泡阶段的事件,如果第三个参数指定为true,则监听的是捕获阶段的事件。低版本IE(6,7,8)不支持捕获阶段的事件监听,只能用attachEven来监听冒泡阶段事件。这不意味着低版本IE没有事件捕获,其实有,只不过没办法去监听而已

attachEvent和addEventListener的对比

  1. 两者都可以为一个元素添加多个事件监听,不会出现覆盖问题
  2. 前者回调函数中this指向window,后者回调函数中this指向当前元素
  3. 前者监听的是事件冒泡,而后者通过第三个参数可以指定为冒泡(默认false)或者捕获(true)
  4. 对于阻止事件冒泡,前者调用e.cancelBubble=true,而后者调用e.stopPropagation()
  5. 事件名不一样:前者“onclick”,而后者“click”
  6. 前者支持IE10及以下(IE11以及以上使用的话,会提示没有这个方法),而后者IE9及以上和非IE浏览器

阻止默认行为

标准写法:

function cancelHandler(event){
    event=event||window.event;//兼容IE
    
    //取消事件相关的默认行为
    if(event.preventDefault)    //标准技术
        event.preventDefault();
    if(event.returnValue)    //兼容IE9之前的IE
        event.returnValue=false;
    return false;    //用于处理使用对象属性注册的处理程序
}

  因为IE6,7,8回调函数的没有传入参数,而是要通过window.event来获取事件对象;而且ff中没有全局的window.event事件对象,所以兼容的写法就是 event || window.event

  dom0级事件(onclick=xxx)中,使用e.returnValue = false【IE9以上不支持】 、e.preventDefault()【IE6,7,8不支持】或者return false【主要用在dom0级事件中,如onclick=xx】都有效

  dom2级事件(addEventListener)中,使用return false无效

  attachEvent中使用e.preventDefault()无效

ps:阻止a标签的默认行为

事件委托

  利用事件冒泡,把对多个子元素的事件监听,转换为对一个父元素的事件监听,可以提升效率(减少内存对象)。其实利用捕获或者冒泡实现都可以,只不过主流浏览器都支持事件冒泡,所以从兼容性的角度来还是选用冒泡。

<ul id="color-list">
    <li>red</li>
    <li>yellow</li>
    <li>blue</li>
    <li>green</li>
    <li>black</li>
    <li>white</li>
</ul>

(function(){
    var color_list = document.getElementById('color-list');
    color_list.addEventListener('click',showColor,false);
    function showColor(e){
        var x = e.target;
        if(x.nodeName.toLowerCase() === 'li'){
            alert('The color is ' + x.innerHTML);
        }
    }
})();

  以上使用委托除了节省了内存外,还有另外一个好处,当动态添加了一个子元素,不需要为这个子元素绑定事件,更加便捷。

事件目标

evt中对于事件对象有三个属性:currentTarget、target和srcElement

currentTarget:代表当前节点,一般与this指向相同。(attachEvent中this指向window)

target和srcElement:实际发生事件的dom对象。ff不支持srcElement,所以兼容的写法是: var target = e.target || e.srcElement

事件其他属性

bubbles:代表当前事件是否会冒泡,除了focus、blur和scroll三种事件不会冒泡之外,其他类型的事件改属性都为true

cancelBubble:默认为false,设置为true时,用于阻止冒泡,对捕获阶段无效,全浏览器支持,但不是标准写法,应尽量使用stopPropagation

stopPropagation() :阻止事件在事件流(先捕获后冒泡)中的传播。一种情况例外,如果在A上捕获事件,里面执行stopPropagation,则A的冒泡回调也会执行:

<div id="a">
    123
    <div id="b">
        456
        <div id="c">
            789
        </div>
    </div>
</div>
<script>
    var a = document.querySelector("#a");
    var b = document.querySelector("#b");
    var c = document.querySelector("#c");

    a.addEventListener('click',(e)=>{
        console.log("a")

    },true)

    b.addEventListener('click',(e)=>{
        console.log("b")
        e.stopPropagation()
    },true)

    c.addEventListener('click',(e)=>{
        console.log("c")
    },true)

    a.addEventListener('click',(e)=>{
        console.log("2 a")
    })

    b.addEventListener('click',(e)=>{
        console.log("2 b")
    })

    c.addEventListener('click',(e)=>{
        console.log("2 c")
    },true)
</script>
点击456,输出 a b 2b。
View Code

stopImmediatePropagation():在阻止事件传播的基础上,同时阻止当前元素上对同一事件的其他回调函数的执行

总结低版本IE与其他浏览器的事件差异

  1. 获取事件对象的方式不同
  2. 取消默认行为的方式不同
  3. 可以检测控制的事件流不同
posted @ 2017-12-05 11:08  HelloHello233  阅读(270)  评论(0编辑  收藏  举报