先通过一段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。