美文网首页
实习第七十天(js事件机制)

实习第七十天(js事件机制)

作者: Artifacts | 来源:发表于2019-12-02 17:06 被阅读0次

    DOM事件流(event flow )存在三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。

    • 事件捕获(event capturing):通俗的理解就是,当鼠标点击或者触发dom事件时,浏览器会从根节点开始由外到内进行事件传播,即点击了子元素,如果父元素通过事件捕获方式注册了对应的事件的话,会先触发父元素绑定的事件。
    • 事件冒泡(dubbed bubbling):什么是“事件冒泡”呢?假设这里有一杯水,水被用某种神奇的方式分成不同颜色的几层。这时,从最底层冒出了一个气泡,气泡会一层一层地上升,直到最顶层。而你不管在水的哪一层观察都可以看到并捕捉到这个气泡。好了,把“水”改成“DOM”,把“气泡”改成“事件”。这就是“事件冒泡”。

    气泡带上了某种信息,会告诉其经过的每一层自己是在哪一层产生的。JavaScript的事件确实会带着这个属性。当程序捕获一个事件的时候,它会知道这个事件来自于页面上哪个元素。 事件委托也就是利用这个原理。
    与事件捕获恰恰相反,事件冒泡顺序是由内到外进行事件传播,直到根节点。能冒泡的事件

    无论是事件捕获还是事件冒泡,它们都有一个共同的行为,就是事件传播,它就像一跟引线,只有通过引线才能将绑在引线上的鞭炮(事件监听器)引爆

    dom标准事件流的触发的先后顺序为:先捕获再冒泡,即当触发dom事件时,会先进行事件捕获,捕获到事件源之后通过事件传播进行事件冒泡。不同的浏览器对此有着不同的实现,IE10及以下不支持捕获型事件,所以就少了一个事件捕获阶段,IE11、Chrome 、Firefox、Safari等浏览器则同时存在。

    用于事件绑定的方法:addEventListener、attachEvent。当然还有其它的事件绑定的方式这里不做介绍。

    addEventListener(event, listener, useCapture)

    • 参数定义:event---(事件名称,如click,不带on),listener---事件监听函数,useCapture---是否采用事件捕获进行事件捕捉,默认为false,即采用事件冒泡方式
      addEventListener在 IE11、Chrome 、Firefox、Safari等浏览器都得到支持。

    attachEvent(event,listener)

    • 参数定义:event---(事件名称,如onclick,带on),listener---事件监听函数。
      attachEvent主要用于IE浏览器,并且仅在IE10及以下才支持,IE11已经废了这个方法了(微软还是挺识趣的,慢慢向标准靠拢)。

    事件捕获与事件冒泡的具体表现行为差异:

    • 事件冒泡
    <html lang="zh-cn">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title>js事件机制</title>
        <style>
            #parent{
                width: 200px;
                height:200px;
                text-align: center;
                line-height: 3;
                background: green;
            }
            #child{
                width: 100px;
                height: 100px;
                margin: 0 auto;
                background: orange;
            }
        </style>
        </head>
    <body>
        <div id="parent">
            父元素
            <div id="child">
                子元素
            </div>
        </div>
        <script type="text/javascript">
            var parent = document.getElementById("parent");
            var child = document.getElementById("child");
        
            document.body.addEventListener("click",function(e){
                console.log("click-body");
            },false);
            
            parent.addEventListener("click",function(e){
                console.log("click-parent");
            },false);
    
            child.addEventListener("click",function(e){
                console.log("click-child");
            },false);
        </script>
    </body>
    </html>
    

    通过"addEventListener"方法,采用事件冒泡方式给dom元素注册click事件,点击子元素如下图所示:


    事件触发顺序是由内到外的,这就是事件冒泡,虽然只点击子元素,但是它的父元素也会触发相应的事件,其实这是合理的,因为子元素在父元素里面,点击子元素也就相当于变相的点击了父元素。
    如果点击子元素不想触发父元素的事件,那就是停止事件传播---event.stopPropagation();
    修改代码,在子元素的监听函数中加入停止事件传播的操作

    child.addEventListener("click",function(e){
      console.log("click-child");
       e.stopPropagation();
    },false);
    

    在点击子元素的时候就只弹出了子元素那条信息,父元素的事件没有触发,因为事件已经停止传播了,冒泡阶段也就停止了。

    • 事件捕获
    var parent = document.getElementById("parent");
            var child = document.getElementById("child");
        
            document.body.addEventListener("click",function(e){
                console.log("click-body");
            },false);
            
            parent.addEventListener("click",function(e){
                console.log("click-parent---事件传播");
            },false);
         
         //新增事件捕获事件代码
            parent.addEventListener("click",function(e){
                console.log("click-parent--事件捕获");
            },true);
    
            child.addEventListener("click",function(e){
                console.log("click-child");
            },false);
    
    输出顺序

    父元素通过事件捕获的方式注册了click事件,所以在事件捕获阶段就会触发,然后到了目标阶段,即事件源,之后进行事件传播,parent同时也用冒泡方式注册了click事件,所以这里会触发冒泡事件,最后到根节点。这就是整个事件流程。



    • 事件委托和事件绑定比较

    “事件委托”的概念很简单,生活中也不乏这样的例子。比如,有三个同事预计会在周一收到快递。为签收快递,有两种办法:一是三个人在公司门口等快递;二是委托给前台代为签收。现实当中,我们大都采用委托的方案(公司也不会容忍那么多员工站在门口就为了等快递)。前台收到快递后,她会判断收件人是谁,然后按照收件人的要求签收,甚至代为付款。这种方案还有一个优势,那就是即使公司里来了新员工(不管多少),前台也会在收到寄给新员工的快递后核实并代为签收。

    1. JQuery中

    $(selector).on(event,childSelector,data,function,map)
    实现委托,一般用于动态生成的元素

    1. js实现通过parent元素给child元素注册click事件
    var parent = document.getElementById("parent");
    var child = document.getElementById("child");
    //target 事件属性可返回事件的目标节点(触发该事件的节点),如生成事件的元素、文档或窗口。
    parent.onclick = function(e){
                if(e.target.id == "child"){
                    console.log("您点击了child元素")
                }
    }
    

    例2

    //document.onclick,从这点就能看出,这个示例把事件委托放到了document上。
    document.onclick = function(event){
        //IE doesn't pass in the event object
        event = event || window.event;
        
        //IE uses srcElement as the target
        var target = event.target || event.srcElement;
        
        switch(target.id){
            case "help-btn":
                    openHelp();
                    break;
            case "save-btn":
                    saveDocument();
                    break;
            case "undo-btn":
                    undoChanges();
                    break;
            //如果有其元素需要处理点击事件,
            //只需要在这里添加不同的case分支就行。
        }
    };
    

    虽然没有直接给child元素注册click事件,可是点击child元素时却弹出了提示信息。
    事件绑定:

    document.getElementById("id").onclick=function(){
       //这里是事件处理代码
    }
    

    事件委托和事件绑定的占用内存对比
      如果一个整体页面里有大量的需要绑定事件的元素,每个元素都要绑定一个函数,而每个函数都是对象,对象就会占用很多内存,内存中的对象越多,性能就越差。

    而事件委托,只在绑定事件的上级元素上绑定函数,次数十分有限(一般每次委托只有一次);另外,在事件被触发时,才会取出触发事件的元素来进一步处理。总体来讲,非常节约内存。

    相关文章

      网友评论

          本文标题:实习第七十天(js事件机制)

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