实现功能:点击按钮触发浮层,点击别处关闭浮层。
- html 代码:
<div id="wrapper" class="wrapper">
<button id="clickMe">点击</button>
<div id="popover" class="popover">
<input type="checkbox">浮层
</div>
</div>
- 部分 css 代码:
.popover{
display: none;
}
1. 方案一 --- 用 DOM Events 实现
- 如上,浮层的样式默认为“不显示 ”。我们监听
button
点击事件,使button
被点击时显示浮层。
clickMe.addEventListener('click', function(){
popover.style.display = 'block'
})
- 实现点别处关闭浮层时,可以监听
document
。
注意:不要监听body
,因为body
是被文档流撑起来的,高度很小,空白处可能取不到body
。
document.addEventListener('click', function(){
popover.style.display = 'none'
})
- 因为点击
button
和popover
时document
也会被点击,导致无法触发浮层。所以要在它们的父元素wrapper
处阻断冒泡。
wrapper.addEventListener('click', function(e){
e.stopPropagation() //停止传播,阻断冒泡
})
2. 方案二 --- 用 jQuery 实现
- 同理,我们改为 jQuery 语句:
$(clickMe).on('click', function(){
$(popover).show()
})
$(wrapper).on('click', function(e){
e.stopPropagation()
})
$(document).on('click', function(){
$(popover).hide()
})
- 同时阻止传播和阻止默认事件
jQuery 提供了一个方便的写法,用false
可以同时阻止传播和阻止默认事件。但此处不可以用,因为会导致无法勾选checkbox
(默认它的动作被阻止)而出现 bug。
$(wrapper).on('click', false) //同时阻止传播和阻止默认事件
// 等价于
$(wrapper).on('click', function(e){
e.preventDefalt()
e.stopPropagation()
})
所以我么平时使用 preventDefault
时一般不要直接放在 div 上。
- 节省内存
document
处于一直被监听的状态,非常浪费内存。为了节省内存,我们可以使它只在浮层出现的时候被监听一次。
$(clickMe).on('click', function(){
$(popover).show()
$(document).one('click', function(){ // 只在 button 被点击时监听 document
$(popover).hide()
})
})
$(wrapper).on('click', function(e){
e.stopPropagation()
})
3. 完善功能
为使浮层更具实用性,我们使其最终实现的功能包括:
- 点击按钮弹出浮层
- 点击别处关闭浮层
- 点击浮层时,浮层不得关闭
- 再次点击按钮,浮层消失
为了更好地学习理解 DOM Events,选择用方案一来实现:
clickMe.addEventListener('click',function(e){
if(popover.style.display === 'none'){ // 若浮层在关闭状态
popover.style.display = 'block' // 显示浮层
e.stopPropagation() // 阻止冒泡
}else{
popover.style.display = 'none' // 否则关闭浮层
}
})
document.addEventListener('click',function(){
popover.style.display = 'none'
})
popover.addEventListener('click',function(e){
e.stopPropagation()
})
但是在调试时发现存在 bug:运行代码后首次点击 button
并不会触发浮层。
后来发现,因为我直接在 js 中用 style
去控制样式,而它是直接去获取元素上的 style
属性的,因此之前写在 css 里的 display
属性它获取不到(除非用 window.getComputedStyle
去获取),首次点击按钮时 display
相当于是空字符串。
4. 优化代码
- 由上可知,除非不得已,我们最好不要在 js 中直接用
style
来控制样式(容易出现 bug 且不好debugger
),而是改用切换class
状态的方法。 - 改进方法:在 css 中添加一个类,只需判断浮层
popover
当前是否包含这个类,然后进行添加和移除操作。
首先在 css 中添加一个类 show
来显示浮层:
.show{
display: block;
}
完整的 js 代码:
clickMe.addEventListener('click', function(e) {
let p1 = document.getElementById('popover')
if (!p1.classList.contains('show')) { // 判断当前类是否包含 show
p1.classList.add('show')
e.stopPropagation() // 停止传播,阻断冒泡
} else {
p1.classList.remove('show')
}
document.addEventListener('click', function() {
p1.classList.remove('show')
})
})
popover.addEventListener('click', function(e) {
e.stopPropagation()
})
网友评论