上一次学习了DOM 的事件,理解了冒泡事件和捕获事件,触发的机制,今天学习一下具体的应用场景,或者说在哪一个地方容易踩坑。css
作一个小demo,点击按钮出现浮层,点击其它地方关闭浮层,写一个简单csssegmentfault
<style> .wrapper{ position:relative; display:inline-block; } .popover{ position:absolute; border:1px solid red; left:100%; top:0; padding:10px; margin-left:10px; background:white; display: none; /*默认隐藏*/ } .popover::before{ position:absolute; content:''; top:5px; right:100%; border:10px solid transparent; border-right-color:red; } .popover::after{ position:absolute; content:''; top:5px; right:100%; border:10px solid transparent; border-right-color:white; margin-right:-1px; } </style> <div id="wrapper" class='wrapper'> <button id="clickMe">点我</button> <div id="popover" class="popover"> <input type="checkbox">浮层 </div> </div> <script> clickMe.addEventListener('click',function(){ popover.style.display = 'block'; }); </script>
那如今我要点击页面空白地方关闭呢?该用什么方法,很容易想到监听文档,以下代码浏览器
document.addEventListener('click',function(){ popover.stely.display = 'none'; });
可是实际上这样写了以后,按钮都失效了,怎么点都没有反应。这是为何呢?
理解上一篇讲的捕获和冒泡事件后就很好理解这点了,能够DOM事件之捕获、冒泡。
咱们没有指定监听是在捕获仍是冒泡阶段,浏览器默认是冒泡阶段,当咱们点击按钮时,捕获阶段没有发生何时,可是冒泡阶段就不同了,首先button
上函数先触发,而后document
上函数也触发了,致使准备出现的浮层又被隐藏了。
那你可能要问,button
上的事件执行了没?其实这两个事件都执行了,只是时间过短,浏览器默认一块儿执行了,能够在里面加一个debugger
,就能够看到了。app
clickMe.addEventListener('click',function(){ popover.style.display = 'block'; });
那该怎么解决呢?最简单的方法是,除了要执行popover.style.display = 'block'
,还要阻止事件传播ide
clickMe.addEventlistener('click',function(){ popover.style.display = 'block'; }); popover.addEventListener('click',function(e){ e.stopPropagation(); });
这里为何添加在按钮的父元素上面呢?若是不添加在父元素上面,点击浮层的时候,浮层也会被关闭。函数
若是页面上有不少监听器的话,这个方法是比较浪费内存的,比较省内存的方法用JQuery 作学习
$(clickMe).on('click',function(){ $(popover).show(); $(document).one('click',function(){ $(popover).hide(); }); }); $(wrapper).on('click',function(e){ e.stopPropagation(); })
一开始不监听,只在popover
`show`的时候监听一次,立刻关掉,这叫作清理战场。$(wrapper).on('click',false)
和下面的代码彻底等价flex
$(wrapper).on('click',function(e){ e.preventDefault(); //阻止默认事件 e.stopPropagation(); //阻止传播 })
可是若是页面中有checkbox
,你在它的父元素任何一层,包括checkbox
本身,添加了组织默认事件那么这个checkbox
就没办法被check
。spa
这里有个问题,若是没有阻止事件传播,向下面这样,会发生什么事情呢?debug
$(clickMe).on('click',function(){ $(popover).show(); $(document).one('click',funtion(){ $(popover).hide(); }); });
固然了,和以前同样,什么事情也不会发生,那当我点击按钮以后里面都发生了那些事情呢?
当我点击了按钮以后,它会作两件事情,首先把popover
`show出来,而后把
hide函数添加到
document上面,当事件传播到
document`,就会又把它给隐藏了。
能够给它添加一个setTimeout()
函数来解决这个问题
$(clickMe).on('click',function(){ $(popover).show(); setTimeout(function(){ $(document).one('click',function(){ $(popover).hide(); }) },0) });
setTimeout(fn,0)
这个0
不是立刻执行,而是尽快执行,具体是在冒泡结束在执行这里的函数,也就是说,当冒泡结束后,在把监听事件添加到document
上面,等待用户下次点击在执行。
<style> .red.active{ background:red; } .blue.active{ background:blue; } .green.active{ background:green; } .yellow.active{ background:yellow; } .orange.active{ background:orange; } .purple.active{ background:purple; } div{ border:1px solid black; display:flex; flex:1; padding:20px; transition:1s; border-radius:100%; } *{ padding:0; margin:0; box-sizing:border-box; } .red{ height:300px; width:300px; } </style> <div class="red"> <div class="blue"> <div class="green"> <div class="yellow"> <div class="orange"> <div class="purple"></div> </div> </div> </div> </div> </div> <script> var n = 1 $('div').on('click',function(e){ setTimeout(function(){ $(e.currentTarget).addClass('active') },n*500) n+=1 }) </script>
总结:
button
和document
,点啥都没反应,由于两个函数都执行了,用阻止事件传播解决了,比较浪费内存button
后在监听document
,关闭了就再也不监听,不阻止事件传播,点啥也没反应,两种解决方法:一种是阻止事件传播,另外一种是添加一个setTimeout()
函数。