前言:虽然精通jquery,但对它的原型javascript却不是很了解,最近在学习javascript中遇到了一些困难,好比冒泡和捕获,不少次被提到,但又不知究竟应用在何处。找到了一些好文章解惑,在这里分享给你们。javascript
quirksmode的一系列文章都不错,通俗易懂,这篇只是一系列中的某一篇,有机会把javascript这系列都翻译给你们。html
原文地址在这里http://www.quirksmode.org/js/events_order.html,句子中有标注“(?)”表示我对这个句子不是很理解,可能有误。正式开始:java
事件的发生顺序jquery
这个问题的起源很是简单,假设你在一个元素中又嵌套了另外一个元素web
----------------------------------- | element1 | | ------------------------- | | |element2 | | | ------------------------- | | | -----------------------------------
:而且二者都有一个onClick事件处理函数(event handler)。若是用户单击元素2,则元素1和元素2的单击事件都会被触发。可是哪个事件先被触发?哪个事件处理函数会被首先执行?换句话说,事件的发生顺序到底如何?浏览器
两种模型安全
不出所料,在那些“不堪回首”(浏览器大战)的日子里,Netscape和微软有两种大相径庭的处理方法:app
这两种事件顺序是截然相反的。Explorer浏览器只支持冒泡事件,Mozilla,Opera7和Konqueror二者都支持。而更古老的opera和iCab二者都不支持dom
捕获型事件函数
当你使用捕获型事件时
| | ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 \ / | | | ------------------------- | | Event CAPTURING | -----------------------------------
:元素1的事件处理函数首先被触发,元素2的事件处理函数最后被触发
冒泡型事件
当你使用冒泡型事件时
/ \ ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 | | | | | ------------------------- | | Event BUBBLING | -----------------------------------
:元素2 的处理函数首先被触发,元素1其次
W3C 模型
W3c明智的在这场争斗中选择了一个择中的方案。任何发生在w3c事件模型中的事件,首是进入捕获阶段,直到达到目标元素,再进入冒泡阶段
| | / \ -----------------| |--| |----------------- | element1 | | | | | | -------------| |--| |----------- | | |element2 \ / | | | | | -------------------------------- | | W3C event model | ------------------------------------------
为一个web开发者,你能够选择是在捕获阶段仍是冒泡阶段绑定事件处理函数,这是经过addEventListener()方法实现的,若是这个函数的最后一个参数是true,则在捕获阶段绑定函数,反之false,在冒泡阶段绑定函数。
假设你要作
element1.addEventListener('click',doSomething2,true)
element2.addEventListener('click',doSomething,false)
若是用户单击元素2,则接下来会发生:
(事件在这里就像一个观光客,由外至内游览,逐渐接近被触发的主要元素,而后又反向离开)
相反的状况是:
element1.addEventListener('click',doSomething2,false)
element2.addEventListener('click',doSomething,false)
如今若是用户点击元素2会发生:
兼容性和传统模式
在支持w3c dom(文档对象模型) 的浏览器中,传统的事件绑定方法是
element1.onclick = doSomething2;
默认被视为在绑定于冒泡阶段
使用冒泡型事件
不多的开发人员会有意识的去使用冒泡型事件或者捕获型事件。在他们今天制做的网页中,没有必要让一个事件由于冒泡而被好几个函数处理。可是有时用户一般会很疑惑,由于在他们只点击了一次鼠标以后出现了许多种状况(多个函数被执行,由于冒泡)。而大多数状况下你仍是但愿你的处理函数相互独立的。当用户点击了某一个元素,发生什么,点击另外一个元素,又对应发生些什么,相互独立,而不由于冒泡连锁。
一直在发生
首先你要明白的是事件捕获或者冒泡一直在发生。若是你给整个页面文档的定义一个通用onclick处理函数
document.onclick = doSomething;
if (document.captureEvents) document.captureEvents(Event.CLICK);
//第二句话我也不知道什么意思,初学者,但愿有能人能解释
在页面上单击任何元素的单击事件,最终会冒泡至页面最高文档层,所以触发那个通用的处理函数,除非以前一个处理函数明确的指出终止冒泡,这样才冒泡才不会传播到整个文档层面
用法(这一小节翻译的很差,由于没有实战,我也不是很理解,能够在留言中补充,我会更新)
由于任何事件传播终止于页面文档(这个最高层),这使默认的事件处理函数变得可能,假设你有这样一个页面
------------------------------------ | document | | --------------- ------------ | | | element1 | | element2 | | | --------------- ------------ | | | ------------------------------------
element1.onclick = doSomething;
element2.onclick = doSomething;
document.onclick = defaultFunction;
如今若是用户单击元素1或者元素2,doSomething()将被执行。若是你愿意的话,若是你不想让事件冒泡至执行defaultFunction(),你能够在这里阻止事件冒泡向上传播,。可是若是用户点击页面上的其余部位,defaultFunction()仍是会被执行。这样的效果或许有时能用的上。
设置页面——使处理函数有范围较大的触发面积,在“拖拽效果”脚本中是必须的。通常来讲在某一个元素层上发生 mousedown事件意味着选择了这个元素,而且使它可以响应mousemove事件。虽然mousedown一般绑定于这个元素层上以免浏览器bug,可是其余二者的事件函数的范围必须是整个页面(?)
记住浏览器学的第一法则(First Law of Browserology)是:一切皆有可能(anything can happen),而且是在你起码有点准备的时候。因此有可能发生的是,用户拖拽时,大幅度在页面上移动他的鼠标,脚本却不能在大幅度中作出反应,以致于鼠标也就再也不停留在元素层上了
因此在这个例子中,事件冒泡很是的有用,由于将你的处理函数放在页面层能保证他们一直能被执行
把它给关了
可是通常状况下,你会想关了全部的冒泡和捕获以保证函数之间不会打扰到对方。除此以外,若是你的文档结构至关的复杂(许多table之间相互嵌套或者诸如此类),你也会为了节省系统资源,而关闭冒泡。此时浏览器不得不检查目标元素的每个祖先,看是否它有一个处理函数。即便一个都没有找到,刚刚的搜索一样花费很多时间
在微软的模型中,你必须设置事件的cancelBubble的属性为true
window.event.cancelBubble = true
在w3c模型中你必须调用事件的stopPropagation()方法
e.stopPropagation()
这会阻止全部冒泡向外传播。而做为跨浏览器解决方案应该这么做:
function doSomething(e)
{
if (!e) var e = window.event;
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
}
在支持cancelBubble属性的浏览器中设置cancelBubble无伤大雅。浏览器会耸一耸肩而后创造一个这个属性。固然这也并不能真正的取消冒泡,但至少能保证这条命令是安全正确的
currentTarget
像咱们以前看到的同样,一个事件用target或者是srcElement属性用来表示事件究竟发生在哪一个目标元素上(即用户最初点击的元素)。在咱们的例子中是元素2,由于咱们单击了它。
很是重要的是,要明白在捕获或者冒泡阶段的目标元素是不变的,它始终与元素2相关联。
可是假设咱们绑定了如下函数
element1.onclick = doSomething;
element2.onclick = doSomething;
若是用户单击元素2, doSomething()会被执行两次。可是你怎么知道哪一个html元素正在响应这个事件?target/srcElement也没有给出线索,但人们老是更倾向于元素2,由于它是引发事件的缘由(由于用户点击的是它)。
为了解决这个问题,w3c 增长了currentTarget这个属性,它就指向正在处理事件的元素:这恰是咱们须要的。很不幸的是微软模型中并无类似的属性
你也可使用”this”关键字。在上面的例子中,它至关于正在处理事件的html元素,就像currentTarget。
微软模型的问题
可是当你使用微软事件绑定模型时,this关键字并不至关于HTML元素。联想缺乏相似currentTarget属性的微软模型(?)——按上面的代码操做的话,你这么作便意味着:
element1.attachEvent('onclick',doSomething)
element2.attachEvent('onclick',doSomething)
你没法确切知道哪个HTML元素正在负责处理事件,这是微软事件绑定模型最严重的问题,对我来讲,这也是我从不使用它的缘由,哪怕是在开发仅供Windows下的IE的应用程序
我但愿可以尽快增长currentTarget相似的属性——或者遵循标准?web开发者们须要这些信息
后记:
由于没有实战过javascript,因此这篇文章有些地方我并非很理解,只能硬生的翻译出来,好比谈拖拽效果的那一段,若是你们有什么补充和疑问能够留言给我,谢谢支持啦!