举一个小例子,说明下对冒泡的理解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>
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; })
效果:
解释:
html和css很好理解。js的意思就是点击$("div")
的时候,添加active
类,即展示了背景颜色。本例中,点击最内层<div id="purple"></div>
的时候,冒泡事件开始询问。
n*1000
后添加active
类,当即执行n+=1
n*1000
后添加active
类,当即执行n+=1
n*1000
后添加active
类,当即执行n+=1
n*1000
后添加active
类,当即执行n+=1
n*1000
后添加active
类,当即执行n+=1
n*1000
后添加active
类,当即执行n+=1
n*1000
后添加active
类,当即执行n+=1
咱们该明白的是,全部事情是一步一步作的,即询问下一个div时,n都是已经加过1了,并且,选择器是$("div")
,因此,全部div都绑定了事件。