在很多网站,经常看到:
点击某个按钮或链接,出现一个弹窗或者展开一个模块,然后点击弹窗(模块)之外的空白,它会被关闭。看过bootstrap和一些其他的源码,有的是使用类似jQuery的.not()
写的,但总感觉这样写不太好,应该怎么写是比较严谨的呢?
在很多网站,经常看到:
点击某个按钮或链接,出现一个弹窗或者展开一个模块,然后点击弹窗(模块)之外的空白,它会被关闭。看过bootstrap和一些其他的源码,有的是使用类似jQuery的.not()
写的,但总感觉这样写不太好,应该怎么写是比较严谨的呢?
来一个javascript 实现的方案吧 :
// 点击其他区域时, 隐藏指定区域(cDom)
document.addEventListener("click", event => {
var cDom = document.querySelector("#filter-header");
var tDom = event.target;
if (cDom == tDom || cDom.contains(tDom)) {
// ...
} else {
cDom.style.display = "none"
}
});
我自己写弹层时,就加了个这个功能。
其实,一般处理方式就是判断点击事件的 e.target 是否为非弹层区域。
不是的话,就关闭弹层。
注意将监听事件绑定在document上。绑定在body上,页面body高度没有超过一屏时,点击非body区域,是不起作用的。
我见过两种方案:
document.body
上的点击事件,如果来源不在目标范围内则关闭;$(document).mouseup(function(e){
var _con = $('#jstreedemo');
if(!_con.is(e.target) && _con.has(e.target).length === 0){
$("#jstreedemo").css("display","none");
}
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Demo</title>
<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<style type="text/css">
#test {
width: 80px;
//height: 60px;
margin:10px auto;
/*border: 1px solid blue;*/
}
#button {
display: block;
width:50px;
margin:10 auto;
}
#content {
width: 60px;
height: 60px;
text-align: center;
margin:10 auto;
/*background: #1d1d1d;*/
border: 1px solid red;
}
#shard {
position: absolute;
display: block;
top: 0px;
left:0px;
width: 100%;
height: 100%;
z-index: -1;
background: #d4f7d4;
}
</style>
</head>
<body>
<div id="shard" ></div>
<div id="test">
<a href="javascript:;" id="button">clickMe</a>
<div id="content" style="display:none">show</div>
</div>
<script>
$('#shard').hide();
$('#button').on('click',function(){
$('#content').css('display','block');
$('#shard').off('click');
$('#shard').hide();
setTimeout(function(){
$('#shard').show();
$('#shard').one('click',function(){
console.log('click ...');
$('#content').css('display','none');
$('#shard').hide();
})
}
, 0);
})
</script>
</body>
</html>
利用事件冒泡
和settimeout
跳出事件队列的方式实现,新get到的技能,希望可以终结这个问题,一起进步哦~
$el_box = $('.box');//弹出层
$el_box.click(function(e){
e.stopPropagation();//阻止弹出层的click事件,防止冒泡到body
});
$(document).one('click',function(e){//我的弹出层元素是动态载入的,使用过后就销毁了,所以用了one,可以使用bind
$el_box.remove();
});
这样如何??
$('html').on('click',function() {
...
});
$('#drop-menu').on('click',function(event){
event.stopPropagation();
);
$('#btn-menu').on('click',function(event){
...
});
正巧,在最近一个项目中我遇到了这个问题。
但我所面对的需求更复杂:要求页面中某一个元素高亮,页面中此元素其余部分变暗,但是页面还是可以滚动。点击此元素其它区域,取消此效果。
看了楼上很多回答,都是在body上做点击时间监听,我的方法并不是这样。
我的方法是在弹窗内建立一个层,覆盖窗口,用它来监听点击事件。
这样做的好处是,将弹窗移除后,相关的事件、DOM都可以一并移除,并且底层的大小可以通过控制父层的position属性,任意更改。
.wapper{
position:relative;
}
将上面这段css去掉之后,就成了一个覆盖整个窗口的mask了。
同 fifsky 可以把弹窗上面的点击事件在最后阻止冒泡,然后点击的时候都消失。
我项目里遇到的问题更复杂一点,是有多个可以显示隐藏的层,点空白处全都消失,这几个层,点空白处全都消失,还要互斥显示。如果在body点击事件里做判断,或者调每个模块的方法感觉有点儿麻烦,不可扩展。
所以我的做法是,点body时,发个广播,注册广播的模块都隐藏,每个模块点击时也都可以发这个广播,监听广播的模块只要判断发广播的对象不是自己,都要隐藏起来。
8 回答5.8k 阅读✓ 已解决
9 回答9.2k 阅读
6 回答4.7k 阅读✓ 已解决
5 回答3.5k 阅读✓ 已解决
3 回答10.3k 阅读✓ 已解决
4 回答7.9k 阅读✓ 已解决
7 回答9.8k 阅读
这是当初在stackoverflow上看到的,非常简单的实现,这里的目标区域就是你的弹出窗口