阻止事件冒泡
W3C的方法是ev.stopPropagation(),IE则是使用ev.cancelBubble = true。
先不谈IE的私有方法,首先讨论一个问题:ev.stopPropagation()真的是阻止事件冒泡吗?
实际上,这个问题需要分两种情况来讨论:
-
DOM0的阻止冒泡事件
还是同心圆的例子,代码如下。
JavaScript:
var div = document.querySelector("div");
var ul = document.querySelector("ul");
var li = document.querySelector("li");
div.onclick = function(ev){
console.log("div");
}
ul.onclick = function(ev){
console.log("ul");
}
li.onclick = function(ev){
console.log("li");
ev.stopPropagation();
}
此时输出结果如下:
可以看到阻止事件冒泡成功了,证明DOM0确实是阻止事件冒泡。
-
DOM2的阻止冒泡事件
还是同心圆的例子,代码如下:
var div = document.querySelector("div");
var ul = document.querySelector("ul");
var li = document.querySelector("li");
div.addEventListener('click',function(){
console.log("div 捕获");
},true);
ul.addEventListener('click',function(ev){
console.log("ul 捕获");
},true);
li.addEventListener('click',function(ev){
console.log("li 捕获");
},true);
div.addEventListener('click',function(ev){
console.log("div 冒泡");
});
ul.addEventListener('click',function(ev){
console.log("ul 冒泡");
});
li.addEventListener('click',function(ev){
console.log("li 冒泡");
});
此时点击内层圆,输出结果如下:
我们将
ul.addEventListener('click',function(ev){
console.log("ul 冒泡");
});
改为
ul.addEventListener('click',function(ev){
console.log("ul 冒泡");
ev.stopPropagation();
});
此时点击内层圆,输出结果如下:
可以看到本来会冒泡到div上的点击事件被阻止了,此时跟DOM0的阻止事件冒泡是一致的。
但是如果我们改为阻止在ul的捕获事件上阻止事件冒泡的话,事件捕获还会进行吗?还是只会阻止冒泡?我们来测试一下,将
ul.addEventListener('click',function(ev){
console.log("ul 捕获");
},true);
改为
ul.addEventListener('click',function(ev){
console.log("ul 捕获");
ev.stopPropagation();
},true);
此时的输出结果如下:
可以看到,不但冒泡的整个阶段被阻止了,而且li的事件捕获也被阻止了。
所以总结一下这两点,ev.stopPropagation()不止可以阻止事件冒泡,如果在捕获阶段使用还可以阻止事件捕获。
那么我们再考虑一种特殊情况:如果ev.stopPropagation()在target阶段执行会是什么情况,代码如下。
JavaScript:
div.addEventListener('click',function(){
console.log("div 捕获");
},true);
ul.addEventListener('click',function(ev){
console.log("ul 捕获");
},true);
li.addEventListener('click',function(ev){
console.log("li 捕获");
ev.stopPropagation();
},true);
div.addEventListener('click',function(ev){
console.log("div 冒泡");
});
ul.addEventListener('click',function(ev){
console.log("ul 冒泡");
});
li.addEventListener('click',function(ev){
console.log("li 冒泡");
});
我们在target上阻止了事件监听,这样整个事件冒泡应该是被阻止的,我们看输出结果:
target的冒泡仍然执行了,其实原因很简单,我们在上一章已经提到了,就不多做赘述了。
阻止事件冒泡的兼容写法:
if(event.stopPropagation){
event.stopPropagation();
}else{
event.cancelBubble = true;
}
阻止默认事件
这个没什么好讲的,用于阻止浏览器默认的事件,比如提交按钮的点击默认提交,a标签的点击跳转等。不过之前遇到过一个问题,在jsp里无法阻止提交按钮的提交事件,最后还是换成了div然后使用form.submit()
提交才通过。
兼容写法如下:
if(event.preventDefault){
// W3C的阻止默认事件
event.preventDefault();
}else{
// IE私有的阻止默认事件
event.returnValue = false;
}
事件流的常见应用:事件委托
事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
阻止事件冒泡应用
有一个很应景的例子,页面有一个弹出框,可拖拽,弹出框内有一个input框,这个框内输入的文字要可以选中。
我们先来实现页面结构和拖拽功能,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
div{
position: absolute;
width: 300px;
height: 100px;
background-color: #2578b5;
box-sizing: border-box;
padding: 30px;
}
input{
width: 100%;
line-height: 1.6em;
font-size: 16px;
}
</style>
</head>
<body>
<div>
<input type="text" value="用于复制的文本">
</div>
<script>
var div = document.querySelector('div');
var input = document.querySelector('input');
div.onmousedown = function(ev){
var mouseLeftDiv = ev.clientX - div.offsetLeft;
var mouseTopDiv = ev.clientY - div.offsetTop;
document.onmousemove = function(ev){
var divLeftBody = ev.clientX - mouseLeftDiv;
var divTopBody = ev.clientY - mouseTopDiv;
var docWidth = document.documentElement.clientWidth;
var docHeight = document.documentElement.clientHeight;
if(divLeftBody <= 0){
divLeftBody = 0;
}else if(divLeftBody >= docWidth - div.offsetWidth){
divLeftBody = docWidth - div.offsetWidth;
};
if(divTopBody <= 0){
divTopBody = 0;
}else if(divTopBody >= docHeight - div.offsetHeight){
divTopBody = docHeight - div.offsetHeight;
};
div.style.left = divLeftBody + 'px';
div.style.top = divTopBody + 'px';
}
document.onmouseup = function(){
document.onmousemove = null;
}
}
</script>
</body>
</html>
此时页面如下:
拖拽功能实现了,但是我们发现想要复制文本的时候,没有复制到,反而也触发了拖拽功能,这就很尴尬了。
这时我们的阻止事件冒泡就起作用了,我们在input框上阻止mousedown事件冒泡到外层,代码如下:
JavaScript:
input.onmousedown = function(ev){
ev.stopPropagation();
}
大功告成,此时既可以复制文本,外层又可以拖拽。
参考资料:
http://www.cnblogs.com/liugang-vip/p/5616484.html
http://www.cnblogs.com/libin-1/p/6368323.html