js中的事件传播过程
引子:
父div添加监听事件,子div设置监听事件,点击子元素,会出现什么结果
事件传播的三个过程,事件捕获阶段、处于目标阶段、事件冒泡阶段。
事件捕获由远及近逐渐靠近事件目标,事件冒泡由事件目标逐渐向上冒泡
那是不是所有的事件都要经历这三个过程呢?其实不然
IE:它认为事件流应该是事件冒泡。
Netscape:它则认为事件流应该是事件捕获。
W3C:首先是事件捕获然后事件冒泡
在支持w3c的浏览器中,程序员可以通过设置addEventListener(type,handler,useCapture)中的userCapture值来决定元素是在冒泡阶段执行事件还是捕获阶段执行,默认为false,即冒泡阶段。
IE没有提供选择,事件只能在冒泡阶段捕获。
偷个图[https://www.w3cin.com/2016/06/03/%E6%B5%8F%E8%A7%88%E5%99%A8%E7%9A%84DOM%E4%BA%8B%E4%BB%B6/]:
IE9、Opera、Firefox、Chrome和Safari都支持DOM事件流。
写个代码测试一下
页面内容很简单,父div子div
<div id="parent">
parent
<div id="child">child</div>
</div>
因为考虑到浏览器兼容性,先写一个跨浏览器事件处理函数
var eventHandler={
addEventHandler:function(ele,type,handler,capture){
if(ele.addEventListener){
ele.addEventListener(type,handler,capture);
}else if(ele.attachEvent){
//ie下是需要加on的
//ele.attachEvent(type,handler);
ele.attachEvent('on'+type,handler);
}else{
ele['on'+type]=handler;
}
},
stopPropagation:function(event){
event=event||window.event;
if(event.stopPropagation){
event.stopPropagation();
}else{
event.cancelBubble=true;
}
},
preventDefault:function(event){
event=event||window.event;
if(event.preventDefault){
event.preventDefault();
}else{
event.returnValue=true;
}
}
}
进入正题,对父子div添加监听函数
window.onload=function(){
var parent=document.getElementById("parent");
var child=document.getElementById("child");
eventHandler.addEventHandler(parent,'click',function(e){
console.log("parent捕获阶段");
},true);
eventHandler.addEventHandler(parent,'click',function(e){
console.log("parent冒泡阶段");
},false);
eventHandler.addEventHandler(child,'click',function(e){
console.log("child冒泡阶段");
},false);
eventHandler.addEventHandler(child,'click',function(e){
console.log("child捕获阶段");
},true);
}
chrome下测试结果:
image.png事件果然是从父div到子div被捕获,然后从子div到父div冒泡。
注意:此处对子div绑定了两个事件,即冒泡事件和捕获事件,这两个事件的执行顺序是按照绑定的先后顺序执行的,如果把两个执行函数替换一下,结果就会先打印child捕获阶段,再打印child冒泡阶段,不信你试试~
ie8下的测试结果:
image.pngie下不存在捕获阶段,直接从冒泡阶段开始,由子div到父div打印事件。此处应该注意,对重复绑定的事件,在IE9以下的浏览器中执行顺序都是反着的,因为IE9开始已经支持addEventListener()方法所以不会在有这个问题了。
比如现在我把事件的执行顺序改为
eventHandler.addEventHandler(parent,'click',function(e){
console.log("parent捕获阶段");
// eventHandler.stopPropagation(e);
},true);
eventHandler.addEventHandler(parent,'click',function(e){
console.log("parent冒泡阶段");
},false);
eventHandler.addEventHandler(child,'click',function(e){
console.log("child捕获阶段");
},true);
eventHandler.addEventHandler(child,'click',function(e){
console.log("child冒泡阶段");
},false);
chrome下的执行结果为:
image.pngie8下的执行结果为:
image.png