先通過一段html程式碼瞭解各個div的從屬關係
<div id='wrapper' class="wrapper">
<button id="clickMe">點我</button>
<div id='popover' class="popover">
浮層
</div>
</div>
複製程式碼
要實現的功能是
- 通過button按鈕點選後開啟浮層
採用對button新增監聽事件,預設隱藏浮層,在使用者點選後展示浮層。
- 點選頁面空白區域關閉浮層 實現過程如下所示
1. 監聽body
首先考慮對body物件新增監聽,內容為點選後隱藏浮層。發現無效後通過對body新增邊框看到body高度是根據其內容變化的,所以只佔螢幕上方很小一部分。
2. 監聽document
-
同樣無效。經分析,在冒泡階段先觸發按鈕事件,但因同時存在對document的監聽,緊接著觸發document監聽,所以仍然無法顯示圖層。
-
進一步思考後,對wrapper新增e.stopPropagation,即停止傳播,由此可阻斷冒泡,即可實現上述功能。
clickMe.addEventListener('click', function(e){
popover.style.display = 'block'
})
wrapper.addEventListener('click', function(e){
e.stopPropagation()
})
document.addEventListener('click', function(){
popover.style.display = 'none'
})
複製程式碼
3. 以上雖然可實現需求,但新增的監聽器過多,考慮減少記憶體的使用,可進行優化:
將對document的監聽全部新增到click事件的內部,並使用one方法只監聽一次點選事件。
$(clickMe).on('click', function() {
$(popover).show()
$(document).one('click', function() {
$(popover).hide()
})
})
$(wrapper).on('click', function(e){
e.stopPropagation()
})
複製程式碼
需注意,在3中若刪除阻斷,仍會出現bug,若執意刪除,則需更改程式碼如下:
$(clickMe).on('click', function() {
$(popover).show()
setTimeout(function() {
$(document).one('click', function() {
$(popover).hide()
})
}, 0)
})
複製程式碼
上述程式碼中,將document監聽放在setTimeout函式中,這裡的setTimeout作用在於讓其中的內容儘快執行而不是立即執行,若不新增則在button被點選之後會立即呼叫show和監聽,此時會立即對popover繫結hide,在冒泡階段便會依序執行show和hide,造成bug。