冒泡事件

举一个小例子,说明下对冒泡的理解javascript

准备工做与目的

首先,先写html,就是一个按钮+一个浮层,再加上点csscss

<body>
    <div id="wrap">
        <button id="clickme">Click Me</button>
        <div id="fuceng">
            gone with the wind
        </div>
    </div>
</body>

冒泡效果

而后,写点js实现功能:点击ClickMe按钮弹出gone with the wind浮层,点击别的地方隐藏浮层html

<script>
    $("#clickme").on("click",function(){
        console.log("clickme-clicked");
        $("#fuceng").show();

    })

    $(document).on("click",function(){
        console.log("document-clicked");
        $("#fuceng").hide();
    })
</script>

不难理解,点击$("#clickme")$("#fuceng") show()出来,点击文档$(document)$("#fuceng") hide()java

问题的产生

在单击$("#clickme")的时候并无显示$("#fuceng"),为何???见下图
点击按钮不显示浮层ide

问题解释:遇到事件时,先按照黑色箭头方向从祖先问到本身:捕捉事件,而后再按照红色箭头从本身问到祖先:冒泡事件。问的内容是:某某元素被xxx(事件名)了,你是否有函数要操做?函数

本例中,没有捕捉阶段,直接到冒泡阶段。$("#clickme")被点击后,操做了本身的函数:$("#fuceng").show();。那为何$("#fuceng")不显示呢???由于冒泡还没结束,问过$("#clickme")后又问到了它的祖先$(document):你的一个子孙被点击了,你有函数要操做吗?有!!!而后操做了它的函数$("#fuceng").hide();,因此又被隐藏了。。。优化

为了显示过程,在两个函数里分别加上console.log,结果见下图。
说明,先执行了$("#clickme")的函数,后执行了$(document)的函数。
冒泡显示和隐藏spa

问题的解决

简单再描述一遍,就是咱们同时在按钮和页面上绑定了onclick事件,结果就是触发按钮的onclick同时也触发了页面的onclick,由于按钮在页面里面。code

其中一个解决方法就是,当触发按钮的onclick时,阻止冒泡事件再往上通知,示意图以下。
阻止冒泡事件示意图htm

代码以下:

<script>
    $("#clickme").on("click",function(){
        console.log("clickme-clicked");
        $("#fuceng").show();
    })

    //新添加的代码
    $("#wrap").on("click",function(e){
        e.stopPropagation();
    })

    $(document).on("click",function(){
        console.log("document-clicked");
        $("#fuceng").hide();
    })
</script>

在按钮的父元素$("#wrap")上添加onclick事件,来阻止按钮的onclick再向上通知。在$("#wrap")上阻止冒泡事件,使得不管在点击按钮仍是显现出来的浮层都不会使浮层消失。

优化

假使页面中有不少个浮层,像上面这样每个浮层都监听一次$(document)会大大的占用内存,因此思路是使用one()方法,只在点击按钮的时候监听一次$(document),代码以下:

<script>
    $("#clickme").on("click",function(e){
        $("#fuceng").show();
        //新增代码
        $(document).one("click",function(){
            $("#fuceng").hide();
        })
    })

    $("#wrap").on("click",function(e){
        e.stopPropagation();
    })
</script>

优化探究

上述优化代码可否简单成下面这样呢?

<script>
    $("#clickme").on("click",function(e){
        $("#fuceng").show();
        //新增代码
        $(document).one("click",function(){
            $("#fuceng").hide();
        })
    })
</script>

你看,我在点击按钮的时候只监听一次$("document"),又没有再点击页面了,应该没问题吧?有问题!!!以下图。
事件执行过程

点击按钮(蓝色箭头),调用里面的函数,执行①、执行②。注意,这里执行②就是再给页面添加了一个点击事件,且,在执行按钮的点击事件时,冒泡事件的追问是中止的。等调用完了,再接着问按钮的父辈、祖辈们按钮被点击了,你有没有函数须要调用啊?又问到了页面,这时候页面是有函数的,就是以前执行的②。

其实,除了使用阻止冒泡的方式阻止事件的传播,还可使用setTimeout方法,使须要绑定给页面的函数在冒泡询问完成后再绑定。

<script>
    $("#clickme").on("click",function(e){
        $("#fuceng").show();
        setTimeout(function(){
            $(document).one("click",function(){
                $("#fuceng").hide();
            })
        },0)
    })
</script>

使用setTimeout展示冒泡过程

html:

<body>
    <div id="red">
        <div id="orange">
            <div id="yellow">
                <div id="green">
                    <div id="blue">
                        <div id="indigo">
                            <div id="purple"></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>

css:

#red.active{
    background: red;
}
#orange.active{
    background: orange;
}
#yellow.active{
    background: yellow;
}
#green.active{
    background: green;
}
#blue.active{
    background: blue;
}
#indigo.active{
    background: indigo;
}
#purple.active{
    background: purple;
}
#purple{
    min-height: 100px;
}
div{
    margin:10px;
    border: 1px solid black;
}

js:

var n=0;
$("div").on("click",function(e){
    setTimeout(function(){
        $(e.currentTarget).addClass("active");
    },n*1000)
    n+=1;
})

效果:
setTimeout冒泡展现

解释:
html和css很好理解。js的意思就是点击$("div")的时候,添加active类,即展示了背景颜色。本例中,点击最内层<div id="purple"></div>的时候,冒泡事件开始询问。

  • purple,等候n*1000后添加active类,当即执行n+=1
  • indigo,等候n*1000后添加active类,当即执行n+=1
  • blue,等候n*1000后添加active类,当即执行n+=1
  • green,等候n*1000后添加active类,当即执行n+=1
  • yellow,等候n*1000后添加active类,当即执行n+=1
  • orange,等候n*1000后添加active类,当即执行n+=1
  • red,等候n*1000后添加active类,当即执行n+=1

咱们该明白的是,全部事情是一步一步作的,即询问下一个div时,n都是已经加过1了,并且,选择器是$("div"),因此,全部div都绑定了事件。

相关文章
相关标签/搜索