概念
我们知道,事件流分两个阶段,在捕获阶段,事件从最外层盒子传到最内层了;在冒泡阶段,事件从最内层
传到最外层。有没有办法阻止事件流传播呢?
我们可以使用 event.stopPropagation()来阻止事件继续传播。event 对象是任何事件处理函数中的事件
对象。
看一个例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
/* 样式表省略 */
</style>
</head>
<body>
<div class="box1" id="box1">
<div class="box2" id="box2">
<div class="box3" id="box3"></div>
</div>
</div>
<script type="text/javascript">
var box1 = document.getElementById("box1");
var box2 = document.getElementById("box2");
var box3 = document.getElementById("box3");
box1.addEventListener("click",function(){
alert("A");
},true);
box2.addEventListener("click",function(event){
event.stopPropagation();
alert("B");
},true);
box3.addEventListener("click",function(){
alert("C");
},true);
</script>
</body>
</html>
在页面上我们制作了三个盒子嵌套的结构,分别是外层盒子 box1、中层盒子 box2、内层盒子 box3。我们
分别监听了它们的捕获阶段的点击事件。
现在如果我们点击最内层盒子,按照正常情况,会依次弹出“A”、“B”、“C”,因为捕获阶段时,事件
从外层到内层传播。
但是现在我们在 box2 的事件处理函数中增加了 event.stopPropagation()语句,这句话的作用是阻止事
件继续传播。当 box2 的事件处理函数执行完毕之后,事件将不再往 box3 盒子传播。我们只会看见两个对话框
依次弹出:“A”、“B”,而不会看见“C”弹出。
我们使用 event.stopPropagation()切断了事件接续传播,那它在实战的时候有什么作用呢?我们来看具
体案例。
举例:悬浮层
我们要制作一个悬浮层特效。所谓悬浮层指的是一个绝对定位的 div 盒子,它像系统对话框一样压盖住页
面的原有内容
我们不用实现非常复杂的页面布局,只需要用一个绝对定位的盒子模拟悬浮层即可,给它设置水平居中、垂
直居中。盒子定位完成之后,给它设置 display:none,此时盒子变的不可见。
在页面上放置一个按钮“显示悬浮层”,我们希望点击这个按钮后,能显示悬浮层。悬浮层显示之后,能够
点击页面任何地方(除在悬浮层上点击)关闭这个悬浮层。
HTML 结构非常简单,只有一个悬浮层盒子和一个按钮:
<div class="superposedlayer" id="superposedlayer"></div>
<button id="btn">显示悬浮层</button>
现在书写 JavaScript 代码,给按钮添加事件监听,让点击按钮之后悬浮层能够打开。
<script type="text/javascript">
var btn = document.getElementById("btn");
var superposedlayer = document.getElementById("superposedlayer");
//显示悬浮层
btn.onclick = function(event){
superposedlayer.style.display = "block";
}
</script>
程序非常简单,首先我们得到按钮和悬浮层。给按钮添加事件监听,当点击按钮之后,设置悬浮层的 display
属性为 block,此时悬浮层可见。
你会感觉编程非常简单,没有任何难度。但是,当我们实现“点击页面任何位置可以关闭悬浮层”会遇见一
定的挑战。代码如下:
<script type="text/javascript">
var btn = document.getElementById("btn");
var superposedlayer = document.getElementById("superposedlayer");
//显示悬浮层
btn.onclick = function(event){
superposedlayer.style.display = "block";
}
//关闭悬浮层
document.onclick = function(){
superposedlayer.style.display = "none";
}
</script>
我们给 document 对象增加了点击事件,document 对象表示整个文档,点击整个文档区域就会关闭悬浮层。
感觉程序很正确,但是此时你会发现,点击“显示炫富层”按钮失效了,悬浮层不能显示了。
这是因为,按钮的点击事件会冒泡到 document 对象上,也就是说,点击按钮的时候,也点击了 document。
此时按照事件传播的顺,会先执行按钮的点击事件即显示悬浮层的语句,然后执行 document 的点击事件即执行
关闭悬浮层。这就是为什么我们点击按钮什么事情也不会发生的原因了,悬浮层被显示,然后瞬间被关闭了。
解决办法就是设置当按钮响应事件后,阻止事件继续冒泡。只要事件不冒泡到 document 对象上,document
的 onclick 事件就不会执行。
代码如下:
//显示悬浮层
btn.onclick = function(event){
//阻止事件继续传播
event.stopPropagation();
superposedlayer.style.display = "block";
}
书写 event.stopPropagation()之后,会发现“弹出悬浮层”按钮又恢复正常了。
但是,程序并没有写完,因为我们又发现了一个 bug:在悬浮层内部点击的时候,悬浮层也被关闭了,这是
不符合预期的,因为用户总会在悬浮层内部进行内容的选择等操作,我们不能让用户在悬浮层内部点击的时候也关闭悬浮层。引发问题的原因非常简单:悬浮层的 onclick 事件冒泡到了 document 对象上。
解决方法就是设置悬浮层的点击事件,让它阻止事件继续传播,这样事件就不会传播到 document 对象上了。
案例的完整代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
.superposedlayer{
position: absolute;
width:600px;
height:300px;
background-color: orange;
top: 50%;
left:50%;
margin-left: -300px;
margin-top: -150px;
display: none;
overflow: hidden;
}
</style>
</head>
<body>
<div class="superposedlayer" id="superposedlayer"></div>
<button id="btn">显示悬浮层</button>
<script type="text/javascript">
var btn = document.getElementById("btn");
var superposedlayer = document.getElementById("superposedlayer");
//显示悬浮层
btn.onclick = function(event){
//阻止事件继续传播
event.stopPropagation();
superposedlayer.style.display = "block";
}
document.onclick = function(){
superposedlayer.style.display = "none";
}
superposedlayer.onclick = function(event){
//阻止事件继续传播
// event.stopPropagation();
}
</script>
</body>
</html>