上一次學習了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()
函數。