您的位置:首页 > Web前端 > JavaScript

javascript dom 事件冒泡与捕获

2010-08-08 21:02 375 查看
没想到今天被这个看似简单的问题给耍了,既然它耍我,我也耍耍它。

DOM中的“捕获”和“冒泡”这两个概念,冒泡我们较为常见,因为所有浏览器都支持事件冒泡;由于只有firefox,chrome,safari支持事件捕获,所以捕获我们用的较少一些,像我以前根本没听说过捕获,何谈使用,我想大部分JS开发者[不包括高手]也像我一样对这个机制不太清楚,那么今天让我们来彻底搞清什么是冒泡,什么又是捕获。

以下是人们一直用的一个比较生动的例子来解释这两种概念:

冒泡:即事件由子元素向祖先元素传播的,就像气泡从水底向水面上浮一样[主流浏览器都支持];

捕获:即事件由祖先元素向子元素传播的,像一个石子儿从水面向水底下沉一样 [IE,opera不支持];

在此称这个解释为传统解释,由于这个比喻还是比较抽象,初学者还是搞不明白它的曼妙之处,思来想去还真的没有再傻瓜点的去解释,不过我还是想了一个我自己认为比上面这个例子更容易理解的解释方式。首先让我们来看一张图。

[caption id="attachment_5" align="alignnone" width="720" caption="事件冒泡,捕获模拟"]

[/caption]

下面让我来解释一下,大家可以把上图设想为有三张纸(white ,red ,green),每张都覆盖在另外一张上面,依次贴在一个白色(pannel) 纸板上,这时你用拳头在A处垂直打一拳下去,结果很明显,白纸最先受力,接着红纸,然后是绿纸,由于受力过程发生在瞬间,给人的感觉是它们同时受力,但如果三张纸换成三个人呢,这就很明显了,肯定是白人先觉得疼,然后是红人,接着是绿人。如果我们把纸抽象成三个嵌套的网页标签,白纸是孙标签,红纸的是父标签,绿纸的是爷标签,拳头相当于鼠标指针,这时你肯定会说,哇,原来如此,是的就是这么简单,三张纸的受力过程也就是网页标签的事件被触发过程,也就是传说中的冒泡,那么什么又是捕获呢?更简单,你把白色(pannel) 纸板反个面,再对着它打一拳,这时纸板先受力,然后,绿->红->白,依次受力,正好和冒泡相反。

由于传统解释只抽像出了受力过程,冒气泡[冒泡]和丢石块[捕获],却把最重要的受力物体给丢掉了,所以给人的感觉就是很模糊。这里把触发事件标签比做三张纸,我想应该会容易理解一些,欢迎拍砖。。。。。。

下面让我们来看一个小例子,来具体说明冒泡和捕获的实际作用。由于今天我们的目的是为了搞清冒泡和捕获,所以不考虑到浏览器兼容性。让我们来用对冒泡和捕获的firefox浏览器来做测试。

[css]
#obj1{width:500px;height:500px;margin:0 auto;background:#009900;}
#obj2{width:400px;height:400px;margin:0 auto;background:#ff0000;}
#obj3{width:300px;height:300px;margin:0 auto;background:#fff;}
[/css]

[html]
<div id="obj1">
<h2>爷爷标签</h2>
<div id="obj2">
<h2>父亲标签</h2>
<div id="obj3">
<h2>孙子标签</h2>
<ul>
<h2>ul</h2>
<li>11111111 <h2></h2></li>
<li>222222<h2></h2></li>
<li>333333<h2></h2></li>
</ul>
</div>
</div>
</div>
[/html]

[javascript]
(function(){
var li = document.getElementsByTagName('li');
var count = 1;
document.getElementsByTagName('ul')[0].addEventListener('click',function(e){
var obj = document.createTextNode(e.target.innerHTML+"->"+count++);
this.getElementsByTagName("h2")[0].insertBefore(obj,null);
},false);

for(i=0;i<li.length;i++){
li[i].addEventListener('click',function(){
var obj = document.createTextNode("->"+count++);
this.getElementsByTagName("h2")[0].insertBefore(obj,null);
},false);
}

var papers = document.getElementsByTagName('div');

for(i=0;i<papers.length;i++){
papers[i].addEventListener('click',function(){
var obj = document.createTextNode("->"+count++);
this.getElementsByTagName("h2")[0].insertBefore(obj,null);
},true);
}
})()
[/javascript]

最后大家可以试着把这个开关,设置为false 或者 true 对比点击标签时数字变化,应该完全可以理解它们的区别,如果还是不明白,可以gtalk我。

说到冒泡和表捕获我们一定不能少了 event 这个后来客,如果少了它就等于三缺一这地主就没法斗了。为什么这样说呢,这个event其实就相当于那个拳头砸下去的第一张受力的纸,在firefox里我们可以通过,event.target 取得这个标签,要注意的是,在ie里它是一个全局变量(在那里都可以直接引用),在firefox里你不得不把它当做响应函数的第一个参数传递进函数体才可以使用,兼容性我们不多说,接着我们的话题,为什么它这么重要?因为,它使用比较广,以下是两个常用的地方。

1:拖动:你可以根据这个event判断是那个标签触发了事件链条(也就是那个标签是第一个被点击的),其中evetn.target就是这个这个标签,这时你可以根据它的class或者其它属性来判断是不是要执行拖动相关函数。

2:列表变色:有一个 ul 下面 有 N 个 li, 如果每个 li 有一个自定义属性 color 当然每个li的这个color颜色不同,要求是让我们鼠标移动到li标签上时取得它的这个color来改变它的背景颜色,我的第一反应是给每个li加上一个onmouseover事件,通过这个事件来处理它的背景颜色。但是问题来了,如果有1000,10000个li同时出来呢?每个都加一个事件,肯定是要通过循环处理,无疑也就影响到效率。那如何改进,答案只有一个,就是:”冒泡“,我们可以只在ul上添加onmouseover事件,这样在ul的事件中获取event对象,鼠标经过那个li,这个event.tartet就代表是那个li标签,效率问题瞬时稀释。。。。。。。最后一点不得不说的是,冒泡和捕获只有标签的重叠部分才可以形成这个链式触发,换句话说,你打了红人,白人不受影响。同理,你打了绿人,红人和白人这时都不疼。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐