做一個小demo,點擊按鈕出現(xiàn)浮層,點擊其它地方關(guān)閉浮層,寫一個簡單css
<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; /*默認(rèn)隱藏*/ } .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> <p id="wrapper" class='wrapper'> <button id="clickMe">點我</button> <p id="popover" class="popover"> <input type="checkbox">浮層 </p> </p> <script> clickMe.addEventListener('click',function(){ popover.style.display = 'block'; }); </script>
那現(xiàn)在我要點擊頁面空白地方關(guān)閉呢?該用什么方法,很容易想到監(jiān)聽文檔,如下代碼
document.addEventListener('click',function(){ popover.stely.display = 'none'; });
但是實際上這樣寫了之后,按鈕都失效了,怎么點都沒有反應(yīng)。這是為什么呢?
理解上一篇講的捕獲和冒泡事件后就很好理解這點了,可以[]()。
我們沒有指定監(jiān)聽是在捕獲還是冒泡階段,瀏覽器默認(rèn)是冒泡階段,當(dāng)我們點擊按鈕時,捕獲階段沒有發(fā)生什么時候,但是冒泡階段就不一樣了,首先button
上函數(shù)先觸發(fā),然后document
上函數(shù)也觸發(fā)了,導(dǎo)致準(zhǔn)備出現(xiàn)的浮層又被隱藏了。
那你可能要問,button
上的事件執(zhí)行了沒?其實這兩個事件都執(zhí)行了,只是時間太短,瀏覽器默認(rèn)一起執(zhí)行了,可以在里面加一個debugger
,就可以看到了。
clickMe.addEventListener('click',function(){ popover.style.display = 'block'; });
那該怎么解決呢?最簡單的方法是,除了要執(zhí)行popover.style.display = 'block'
,還要阻止事件傳播
clickMe.addEventlistener('click',function(){ popover.style.display = 'block'; }); popover.addEventListener('click',function(e){ e.stopPropagation(); });
這里為什么添加在按鈕的父元素上面呢?如果不添加在父元素上面,點擊浮層的時候,浮層也會被關(guān)閉。
如果頁面上有很多監(jiān)聽器的話,這個方法是比較浪費內(nèi)存的,比較省內(nèi)存的方法用JQuery 做
$(clickMe).on('click',function(){ $(popover).show(); $(document).one('click',function(){ $(popover).hide(); }); }); $(wrapper).on('click',function(e){ e.stopPropagation(); })
一開始不監(jiān)聽,只在popover
`show`的時候監(jiān)聽一次,馬上關(guān)掉,這叫做清理戰(zhàn)場。$(wrapper).on('click',false)
和下面的代碼完全等價
$(wrapper).on('click',function(e){ e.preventDefault(); //阻止默認(rèn)事件 e.stopPropagation(); //阻止傳播 })
但是如果頁面中有checkbox
,你在它的父元素任何一層,包括checkbox
自己,添加了組織默認(rèn)事件那么這個checkbox
就沒辦法被check
。
這里有個問題,如果沒有阻止事件傳播,向下面這樣,會發(fā)生什么事情呢?
$(clickMe).on('click',function(){ $(popover).show(); $(document).one('click',funtion(){ $(popover).hide(); }); });
當(dāng)然了,和之前一樣,什么事情也不會發(fā)生,那當(dāng)我點擊按鈕之后里面都發(fā)生了那些事情呢?
當(dāng)我點擊了按鈕之后,它會做兩件事情,首先把popover
`show出來,然后把
hide函數(shù)添加到
document上面,當(dāng)事件傳播到
document`,就會又把它給隱藏了。
可以給它添加一個setTimeout()
函數(shù)來解決這個問題
$(clickMe).on('click',function(){ $(popover).show(); setTimeout(function(){ $(document).one('click',function(){ $(popover).hide(); }) },0) });
setTimeout(fn,0)
這個0
不是馬上執(zhí)行,而是盡快執(zhí)行,具體是在冒泡結(jié)束在執(zhí)行這里的函數(shù),也就是說,當(dāng)冒泡結(jié)束后,在把監(jiān)聽事件添加到document
上面,等待用戶下次點擊在執(zhí)行。
總結(jié):
同時監(jiān)聽button
和document
,點啥都沒反應(yīng),因為兩個函數(shù)都執(zhí)行了,用阻止事件傳播解決了,比較浪費內(nèi)存
好一定的方法是用jQuery 做,點擊button
后在監(jiān)聽document
,關(guān)閉了就不再監(jiān)聽,不阻止事件傳播,點啥也沒反應(yīng),兩種解決方法:一種是阻止事件傳播,另一種是添加一個setTimeout()
函數(shù)。
相信看了本文案例你已經(jīng)掌握了方法,更多精彩請關(guān)注Gxl網(wǎng)其它相關(guān)文章!
推薦閱讀:
React-router v4使用步驟詳解
Chart.js輕量級圖表庫使用案例解析
Chart.js 輕量級HTML5圖表繪制工具庫使用步驟詳解
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com