美文网首页一本正经学前端
js中的事件传播过程

js中的事件传播过程

作者: 胡思乱想的Alice | 来源:发表于2017-10-10 12:05 被阅读63次

    引子:
    父div添加监听事件,子div设置监听事件,点击子元素,会出现什么结果

    事件传播的三个过程,事件捕获阶段、处于目标阶段、事件冒泡阶段。
    事件捕获由远及近逐渐靠近事件目标,事件冒泡由事件目标逐渐向上冒泡
    那是不是所有的事件都要经历这三个过程呢?其实不然

    IE:它认为事件流应该是事件冒泡。
    Netscape:它则认为事件流应该是事件捕获。
    W3C:首先是事件捕获然后事件冒泡

    在支持w3c的浏览器中,程序员可以通过设置addEventListener(type,handler,useCapture)中的userCapture值来决定元素是在冒泡阶段执行事件还是捕获阶段执行,默认为false,即冒泡阶段。
    IE没有提供选择,事件只能在冒泡阶段捕获。
    偷个图[https://www.w3cin.com/2016/06/03/%E6%B5%8F%E8%A7%88%E5%99%A8%E7%9A%84DOM%E4%BA%8B%E4%BB%B6/]

    事件传播三个阶段
    IE9、Opera、Firefox、Chrome和Safari都支持DOM事件流。
    写个代码测试一下
    页面内容很简单,父div子div
    <div id="parent">
            parent
            <div id="child">child</div>
        </div>
    

    因为考虑到浏览器兼容性,先写一个跨浏览器事件处理函数

    var eventHandler={
                addEventHandler:function(ele,type,handler,capture){
                    if(ele.addEventListener){
                        ele.addEventListener(type,handler,capture);
                    }else if(ele.attachEvent){
                        //ie下是需要加on的
                        //ele.attachEvent(type,handler);
                        ele.attachEvent('on'+type,handler);
                    }else{
                        ele['on'+type]=handler;
                    }
                },
                stopPropagation:function(event){
                    event=event||window.event;
                    if(event.stopPropagation){
                        event.stopPropagation();
                    }else{
                        event.cancelBubble=true;
                    }
                },
                preventDefault:function(event){
                    event=event||window.event;
                    if(event.preventDefault){
                        event.preventDefault();
                    }else{
                        event.returnValue=true;
                    }
                }
            }
    

    进入正题,对父子div添加监听函数

    window.onload=function(){
                var parent=document.getElementById("parent");
                var child=document.getElementById("child");
                eventHandler.addEventHandler(parent,'click',function(e){
                    console.log("parent捕获阶段");
                },true);
                eventHandler.addEventHandler(parent,'click',function(e){
                    console.log("parent冒泡阶段");
                },false);
                eventHandler.addEventHandler(child,'click',function(e){
                    console.log("child冒泡阶段");
                },false);
                eventHandler.addEventHandler(child,'click',function(e){
                    console.log("child捕获阶段");
                },true);
            }
    

    chrome下测试结果:

    image.png

    事件果然是从父div到子div被捕获,然后从子div到父div冒泡。
    注意:此处对子div绑定了两个事件,即冒泡事件和捕获事件,这两个事件的执行顺序是按照绑定的先后顺序执行的,如果把两个执行函数替换一下,结果就会先打印child捕获阶段,再打印child冒泡阶段,不信你试试~

    ie8下的测试结果:

    image.png

    ie下不存在捕获阶段,直接从冒泡阶段开始,由子div到父div打印事件。此处应该注意,对重复绑定的事件,在IE9以下的浏览器中执行顺序都是反着的,因为IE9开始已经支持addEventListener()方法所以不会在有这个问题了。
    比如现在我把事件的执行顺序改为

    eventHandler.addEventHandler(parent,'click',function(e){
                    console.log("parent捕获阶段");
                    // eventHandler.stopPropagation(e);
                },true);
                eventHandler.addEventHandler(parent,'click',function(e){
                    console.log("parent冒泡阶段");
                },false);
                eventHandler.addEventHandler(child,'click',function(e){
                    console.log("child捕获阶段");
                },true);
                eventHandler.addEventHandler(child,'click',function(e){
                    console.log("child冒泡阶段");
                },false);
    

    chrome下的执行结果为:

    image.png

    ie8下的执行结果为:

    image.png

    相关文章

      网友评论

        本文标题:js中的事件传播过程

        本文链接:https://www.haomeiwen.com/subject/cnrvyxtx.html