Javascript事件冒泡和捕获的应用
前言
上一篇文章已经谈了事件冒泡和捕获的机制,这一篇我们说下这两个机制的具体应用,在这之前我们需要先了解一个东西:HTML DOM Event 对象。
正如w3school里面讲的,Event 对象代表事件的状态,比如事件发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态等等。
事件通常与函数结合使用,函数在事件发生后被执行。
标准Event的属性
下面列出了DOM2 事件标准定义的属性
- bubbles:返回布尔值,指示事件是否是起泡事件类型;
- cancelable:返回布尔值,指示事件是否可拥可取消的默认动作;
- currentTarget:返回其事件监听器触发该事件的元素;
- eventPhase:返回事件传播的当前阶段;
- target:返回触发此事件的元素(事件的目标节点);
- timeStamp:返回事件生成的日期和时间;
- type:返回当前Event 对象表示的事件的名称。
我们通过一段代码来查看标准Event的属性:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20window.onload = function() {
//冒泡方式
document.getElementById("child2").addEventListener("click",function(event){
if(event.eventPhase == event.AT_TARGET){ //正常事件派发
console.log("正常事件派发,是否冒泡:"+ event.bubbles +" 是否可拥可取消默认动作:" + event.cancelable +" 产生事件的节点:" + event.target.id +" 当前节点:"+event.currentTarget.id);
}
if(event.eventPhase == event.BUBBLING_PHASE){ //冒泡阶段
console.log("冒泡阶段,是否冒泡:"+ event.bubbles +" 是否可拥可取消默认动作:" + event.cancelable +" 产生事件的节点:" + event.target.id +" 当前节点:"+event.currentTarget.id);
}
}, false);
//捕获方式
document.getElementById("child1").addEventListener("click",function(event){
if(event.eventPhase == event.CAPTURING_PHASE){ //捕获阶段
console.log("捕获阶段,是否冒泡:"+ event.bubbles +" 是否可拥可取消默认动作:" + event.cancelable +" 产生事件的节点:" + event.target.id +" 当前节点:"+event.currentTarget.id);
}
if(event.eventPhase == event.AT_TARGET){ //正常事件派发
console.log("正常事件派发,是否冒泡:"+ event.bubbles +" 是否可拥可取消默认动作:" + event.cancelable +" 产生事件的节点:" + event.target.id +" 当前节点:"+event.currentTarget.id);
}
}, true);
}
1 | <div id="parent"> |
分别点击 span1、span2、child1、child2 得到如下输出:1
2
3
4捕获阶段,是否冒泡:true 是否可拥可取消默认动作:true 产生事件的节点:span1 当前节点:child1
冒泡阶段,是否冒泡:true 是否可拥可取消默认动作:true 产生事件的节点:span2 当前节点:child2
正常事件派发,是否冒泡:true 是否可拥可取消默认动作:true 产生事件的节点:child1 当前节点:child1
正常事件派发,是否冒泡:true 是否可拥可取消默认动作:true 产生事件的节点:child2 当前节点:child2
标准Event的方法
关于事件冒泡,下面讨论一下两个重要事件方法:
- preventDefault():通知浏览器不要执行与事件关联的默认动作;
- stopPropagation():通知浏览器不再冒泡事件。
关于这两个方法我们看一段代码:1
2
3
4
5<div id="parent">parent
<div id="child">child
<a id="a" href="http://www.baidu.com/">baidu.</a>
</div>
</div>
1 | window.onload = function() { |
点击”baidu.”,会先后弹出”a”和”child”;
点击”child”,只会弹出”child”;
点击”parent”,只会弹出”parent”。
- 解析:
1、虽然a标签定义了自己的href链接地址,但是preventDefault()阻止了a的默认行为;
2、虽然a标签的点击里执行了preventDefault()方法,但是这个方法后面的弹出代码照样执行了;
3、点击a时,事件由a冒泡到child,所以child能够弹出;
4、点击a和child时,并没有弹出parent,说明事件冒泡在child被阻止了。
谈到这里,我们再谈一下 return 这个关键字,下面继续看一段代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14window.onload = function() {
document.getElementById("parent").addEventListener("click",function(event){
alert('parent');
});
document.getElementById("child").addEventListener("click",function(event){
return false;
alert("child");
});
document.getElementById("a").addEventListener("click",function(event){
return true;
//return false;
alert("a");
});
}
点击”baidu.”,会先弹出”parent”,后跳转到百度网页;
点击”child”,只会弹出”parent”。
解析:
1、return true or false阻止了执行alert(“a”),但是没能阻止跳转这个默认行为;
2、return阻止了后面的代码的运行,但是不阻止事件冒泡。总结
1、event.stopPropagation():阻止了事件冒泡,但不会阻击默认行为(执行了超链接的跳转);
2、event.preventDefault():不阻击事件冒泡,但阻击默认行为(执行了所有弹框,却没有执行超链接跳转);
3、return true or false:不阻止事件冒泡,不阻止默认行为(示例代码是没有阻止,实际上是可以阻止的,后面单独一篇文章介绍return true/false),但阻止了后面代码的执行。
最后顺便记录一下事件流模型的浏览器差异,这篇文章的所有代码都以W3C的为准:1
2
3
4
5
6IE W3C
event.cancelBubble === stoppopagation() //阻止冒泡
event.returnValue === preventDefault() //停止默认事件
attachEvent() === addEventListener //增加事件监听
detachEvent() === removeEventListener //移除事件
fireEvent() === createEvent(),initEvent(),dispatchEvent() //触发事件
感谢您的阅读,有不足之处请在评论为我指出。
参考资料
[1]:事件创建过程
版权声明:本文为博主原创文章,未经博主允许不得转载。本文地址 http://yangyuji.github.io/2015/05/27/javascript-event-use/