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
20
window.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
2
3
4
5
6
7
8
<div id="parent">
<div id="child1">child1
<span id="span1">span1.</span>
</div>
<div id="child2">child2
<span id="span2">span2.</span>
</div>
</div>

分别点击 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
2
3
4
5
6
7
8
9
10
11
12
13
window.onload = function() {  
document.getElementById("parent").addEventListener("click",function(event){
alert('parent');
});
document.getElementById("child").addEventListener("click",function(event){
alert('child');
event.stopPropagation(); //阻止冒泡
});
document.getElementById("a").addEventListener("click",function(event){
event.preventDefault();  //阻止默认行为
alert("a");
});
}

点击”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
14
window.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
6
IE                           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/