上个图复习一下:
1. 点击别处关闭图层
html:
<body>
<div id="wrapper" class="wrapper">
<button id="clickMe" >点我</button>
<div id="popover" class="popover">浮层</div>
</div>
</body>
css:
.wrapper{
border: 1px solid red;
position: relative;
display: inline-block;
}
.popover{
border: 1px solid black;
position: absolute;
left: 100%;
white-space: nowrap;
top: 0;
margin-left: 20px;
padding: 10px;
}
.popover::before{
content: '';
border: 10px solid transparent;
border-right-color: black;
position: absolute;
right: 100%;
top: 0;
}
.popover::after{
content: '';
border: 10px solid transparent;
border-right-color: white;
position: absolute;
right: 100%;
top: 0;
margin-left: 100px; /* 问题1: 此句无任何效果??? */
margin-right: -1px;
}
js思路:
js版本1.0:
clickMe.addEventListener('click',function(){
popover.style.display = 'block'
})
document.body.addEventListener('click',function(){
popover.style.display = 'none'
console.log(1)
})
document.body.addEventListener-将外部区域事件添加到body上。
问题:body的高度有内部文档流的高度总和决定,实际点击时有问题。
js版本1.1:
//将外部区域事件添加到document上
document.addEventListener('click',function(){
popover.style.display = 'none'
console.log(2)
})
//将外部区域事件添加到html上
document.documentElement.addEventListener('click',function(){
popover.style.display = 'none'
console.log(3)
})
将外部区域事件添加到document和html上能达到点击外部区域的要求;
问题:实际点击 clickMe 浮层并没有出现;
采用debugger调试法,如下:
clickMe.addEventListener('click',function(){
popover.style.display = 'block'
debugger
})
document.addEventListener('click',function(){
popover.style.display = 'none'
console.log(2)
})
事件过程见下图:
js版本2.0---阻止事件冒泡:
clickMe.addEventListener('click',function(e){
popover.style.display = 'block'
e.stopPropagation()
})
document.addEventListener('click',function(){
popover.style.display = 'none'
console.log(2)
})
event.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'
console.log(2)
})
将event.stopPropagation() 添加在 元素wrapper 上;
上述改进方案基本实现了要求,不过还有点问题‘
问题:document 上每添加一个事件,都要好用一点内存,如果document 上的事件很多,会严重耗费资源。。。。。。
js版本3.0---jQuery的方案:
<!DOCTYPE html>
<html lang="zh-Hans">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="./style.css">
<script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
</head>
<body>
<div id="wrapper" class="wrapper">
<button id="clickMe" >点我</button>
<div id="popover" class="popover">
<input type="checkbox">浮层
</div>
</div>
</body>
<script src="main.js"></script>
</html>
$(clickMe).on('click',function(){
$(popover).show()
})
$(wrapper).on('click',false)
// 等价于---
// $(wrapper).on('click',function(e){
// e.preventDefault()
// e.stopPropagation()
// })
$(document).on('click',function(){
$(popover).hide()
})
以上采用jQuery重新实现2.0版本,
$(wrapper).on('click',false)----既阻止默认事件,又阻止事件传播;
阻止默认事件 会引起一个问题---<input type="checkbox">
无法被选中;因此,是使用阻止默认事件是得注意范围;
改为:
$(wrapper).on('click',function(e){
e.stopPropagation()
})
js版本4.0---节省内存资源:
$(clickMe).on('click',function(){
$(popover).show()
$(document).one('click',function(){
$(popover).hide()
})
})
$(wrapper).on('click',function(e){
e.stopPropagation()
})
$(document).one('click',function(){})----只监听一次;
以上只在点击 clickMe元素 后才开始监听一次 document 点击,完成一次监听后就清理了,这样就能少占用资源了;
js版本4.1---节省内存资源---优化尝试:
$(clickMe).on('click',function(){
$(popover).show()
$(document).one('click',function(){
$(popover).hide()
})
})
省去阻止冒泡事件后发现,点击 clickMe 浮层并没有出现????
测试:
$(clickMe).on('click',function(){
$(popover).show()
console.log('show')
$(document).one('click',function(){
console.log('我觉得点击clickMe时,这里应该不会执行')
console.log('hide')
$(popover).hide()
})
})
测试结果:第一次点击 clickMe 时,$(popover).hide()
就已经执行了????
图解如下:
解决方法:1-添加阻止冒泡事件;2-设定一个定时器来延时(改变执行次序)
方法2如下:
$(clickMe).on('click',function(){
$(popover).show()
console.log('show')
setTimeout(function(){
$(document).one('click',function(){
console.log('我觉得点击clickMe时,这里应该不会执行')
console.log('hide')
$(popover).hide()
})
},0)
})
注意上述 setTimeout 中的事件设定为0ms,但是,依然可以达到改变执行时序的效果,也就是说,setTimeout 会在当前的代码执行完后才开始计算延时时间;
测试:
结果:
//点击clickMe时
show
点击clickMe事件走到了document
添加 one click
点击clickMe事件走到了document
//点击document时
我觉得点击clickMe时,这里应该不会执行
hide
测试:
<!DOCTYPE html>
<html>
<head>
<script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div class="red">
<div class="blue">
<div class="green">
<div class="yellow">
<div class="orange">
<div class="purple"></div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
div{
padding: 20px;
border: 1px solid black;
/* border-radius: 50%; */
transition: all 0.5s;
display: flex;
flex: 1;
}
.red{
width: 100vw;
height: 100vw;
}
.red.active{
background-color: red;
}
.blue.active{
background-color: blue;
}
.green.active{
background-color: green;
}
.yellow.active{
background-color: yellow;
}
.orange.active{
background-color: orange;
}
.purple.active{
background-color: purple;
}
var n=0
$('div').on('click',function(e){
setTimeout(function(){
$(e.currentTarget).addClass('active')
console.log(n)
},n*500)
n=n+1
})