`
jsczxy2
  • 浏览: 1277599 次
  • 性别: Icon_minigender_1
  • 来自: 常州
文章分类
社区版块
存档分类
最新评论

生动详细解释javascript的冒泡和捕获,包懂包会

阅读更多

原文地址在这里http://www.quirksmode.org/js/events_order.html,句子中有标注“(?)”表示我对这个句子不是很理解,可能有误。正式开始:

事件的发生顺序

这个问题的起源非常简单,假设你在一个元素中又嵌套了另一个元素

-----------------------------------
| element1                        |
|   -------------------------     |
|   |element2               |     |
|   -------------------------     |
|                                 |
-----------------------------------

:并且两者都有一个onClick事件处理函数(event handler)。如果用户单击元素2,则元素1和元素2的单击事件都会被触发。但是哪一个事件先被触发?哪一个事件处理函数会被首先执行?换句话说,事件的发生顺序到底如何?

 

两种模型

不出所料,在那些“不堪回首”(浏览器大战)的日子里,Netscape和微软有两种截然不同的处理方法:

  • Netscape主张元素1的事件首先发生,这种事件发生顺序被称为捕获型
  • 微软则保持元素2具有优先权,这种事件顺序被称为冒泡型

这两种事件顺序是截然相反的。Explorer浏览器只支持冒泡事件,Mozilla,Opera7和Konqueror两者都支持。而更古老的opera和iCab两者都不支持

 

捕获型事件

当你使用捕获型事件时

               | |
---------------| |-----------------
| 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,则接下来会发生:

(事件在这里就像一个观光客,由外至内游览,逐渐接近被触发的主要元素,然后又反向离开)

  1. 单击事件首先进入捕获阶段开始(逐渐接近元素2的方向)。查看元素2的祖先元素中是否有在捕获阶段有onclick处理函数的
  2. 发现元素1有一个,于是doSomething2被执行
  3. 事件检查到目标自己(元素2),捕获阶段没有发现更多的处理函数了。事件开始进入冒泡阶段,想当然执行doSomething(),这个绑定于元素2冒泡阶段的函数。
  4. 事件向远离元素2的方向,查看是否有任何祖先元素在冒泡阶段绑定了一个处理函数。没有这样的情况,所以什么也没有发生

相反的情况是:

element1.addEventListener('click',doSomething2,false)

element2.addEventListener('click',doSomething,false)

现在如果用户点击元素2会发生:

  1. 单击事件进入捕获阶段。查看元素2的祖先元素中是否有在捕获阶段有onclick处理函数的,结果一无所获
  2. 事件检查到目标自己。事件开始进入冒泡阶段,并且执行绑定于元素2冒泡阶段的函数。doSomething()
  3. 事件开始远离目标,检查元素2的祖先元素中是否有在冒泡阶段绑定了处理函数的
  4. 发现了一个,于是元素1的doSomething2()被执行

兼容性和传统模式

在支持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),并且是在你起码有点准备的时候。所以有可能发生的是,用户拖拽时,大幅度在页面上移动他的鼠标,脚本却不能在大幅度中做出反应,以至于鼠标也就不再停留在元素层上了

  • 如果onmouseover处理函数绑定在元素层上,这个元素层不会再对鼠标的移动有任何反应,这会让用户觉得奇怪
  • 如果onmouseup处理函数绑定在元素层上,事件也不能被触发,后果是,用户想放下这个元素层后,元素层持续对鼠标移动做出反应。这会引起(用户)更多的迷惑(?)

所以在这个例子中,事件冒泡非常的有用,因为将你的处理函数放在页面层能保证他们一直能被执行

 

把它给关了

但是一般情况下,你会想关了所有的冒泡和捕获以保证函数之间不会打扰到对方。除此之外,如果你的文档结构相当的复杂(许多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的应用程序

分享到:
评论

相关推荐

    2022年生动详细解释javascript的冒泡和捕获.docx

    JavaScript中的事件冒泡和事件捕获是事件处理的重要概念,它们在DOM(文档对象模型)中定义了事件触发的顺序。事件冒泡和捕获是两种不同的事件传播机制,它们在不同浏览器的历史发展中曾导致兼容性问题,但现在已经...

    javascript 网页特效手册和程序员常用javascript

    4. **事件处理**:理解事件机制,如事件监听器、事件冒泡和事件捕获,以及如何绑定和触发事件。 5. **实践应用**:通过实际项目或练习来应用所学知识,不断巩固和提升技能。 6. **兼容性考虑**:由于JavaScript的...

    JavaScript精彩网页特效实例

    JavaScript是一种广泛应用于网页和互联网应用的编程语言,它赋予了网页动态交互的能力,使得用户界面更加生动、用户体验更佳。本篇文章将详细探讨JavaScript在创建精彩网页特效中的应用实例。 一、JavaScript基础 ...

    Head First Javascript Programming(英文版).pdf

    此外,还会讲解事件冒泡和事件捕获机制,以及如何使用事件委托优化代码。 异步编程是JavaScript的一大特色,书中涵盖了回调函数、Promise和async/await的使用,帮助读者解决回调地狱问题,提升代码的可读性和可维护...

    JavaScript傻瓜指南下载

    学习如何绑定和解绑事件,以及使用事件冒泡和事件捕获。 6. **AJAX**:异步JavaScript和XML,虽然现在XML使用较少,但AJAX技术仍然是实现网页无刷新通信的关键。了解XMLHttpRequest对象的使用和fetch API。 7. **...

    悟透JavaScript-pdf版

    《悟透JavaScript》是李战撰写的一本JavaScript教程,它以其独特的讲解方式和生动的语言吸引了众多读者。这本书旨在帮助读者深入理解JavaScript这门强大的编程语言,不仅覆盖了基础概念,还涉及了高级特性,使读者...

    javascript教程和例子

    JavaScript,简称为JS,是一种广泛应用于网页和网络应用开发的脚本语言,它主要负责实现客户端的交互功能,使得用户与网页之间的互动更加生动和高效。在这个“javascript教程和例子”中,虽然教程部分可能不够深入,...

    javascript特效代码大全

    - **事件委托**:使用事件冒泡或捕获机制,减少事件处理器的数量,提高性能。 10. **Web组件** - **自定义元素**:利用Web Components API创建可复用的自定义HTML标签。 - **阴影DOM**:封装组件的样式和结构,...

    21天精通JavaScript PPT

    理解和掌握事件模型(如事件冒泡和事件捕获)以及事件处理器的使用是关键。 5. **AJAX与Fetch**:为了实现异步数据交换,JavaScript提供了AJAX(Asynchronous JavaScript and XML)技术,现在更常见的是使用Fetch ...

    JavaScript网页开发体验式教程

    - 事件冒泡和事件捕获:理解事件处理的两种模式,以及如何选择合适的事件处理方式。 4. **AJAX与异步通信** - AJAX(Asynchronous JavaScript and XML)允许在不刷新整个页面的情况下与服务器交换数据并更新部分...

    javascript精粹(源代码).rar

    6. **事件处理**:JavaScript与DOM(文档对象模型)交互,通过事件监听、事件冒泡和事件委托等技术实现用户交互。 7. **异步编程**:JavaScript的非阻塞I/O特性使其在处理网络请求、定时任务等方面具有优势,...

    Head First JavaScript2017年袁国中译文版本

    《Head First JavaScript 2017年袁国中译文版本》是一本深入浅出的JavaScript编程指南,专为初学者和有经验的开发者设计,旨在帮助读者通过一种直观、生动的方式掌握JavaScript的核心概念和技能。由知名的编程教育...

    javascript学习资料

    事件模型分为DOM0级和DOM2级,理解事件冒泡和事件捕获原理也很重要。 6. **DOM操作**:Document Object Model (DOM)是HTML和XML文档的抽象表示,JavaScript可以通过DOM API来修改网页内容。熟悉`getElementById`、`...

    JavaScript精彩网页特效实例精粹

    理解事件冒泡和事件捕获的概念也至关重要,它们有助于我们更精确地控制事件的触发和处理。 动画效果是网页特效的亮点。JavaScript可以实现基于时间的动画,通过改变CSS属性实现平滑的过渡效果,如淡入淡出、滑动...

    JavaScript特效(新)

    此外,了解事件冒泡和事件捕获机制也是掌握事件处理的关键。 动画是JavaScript特效的重头戏。通过改变CSS属性(如`transform`和`opacity`),可以实现平滑的过渡和动画效果。`requestAnimationFrame`函数用于在...

    Javascript教程.rar

    - 事件冒泡和事件捕获是事件处理的两种模式。 9. **异步编程** - 回调函数、Promise和async/await是JavaScript处理异步操作的主要方式。 - 异步编程有助于避免阻塞主线程,提高应用性能。 10. **ES6及新特性** ...

    javascript 源码

    5. **第25章**:可能讲解了JavaScript的事件处理,包括DOM事件、事件冒泡、事件捕获和事件监听器,这些都是构建交互式Web应用的基础。 6. **第16章**:可能涵盖了DOM(Document Object Model)操作,包括元素选择、...

    javascript 特效 学习它的好教材

    JavaScript特效是网页动态效果的核心技术,它为网页增添生动性和互动性,极大地提升了用户体验。学习JavaScript特效对于前端开发者来说至关重要,因为这不仅涉及到基础的DOM操作、事件处理,还涵盖CSS样式操纵、动画...

    JavaScript 语言用法指南,语法详细介绍,中文版的哦

    事件模型包括冒泡、捕获和目标阶段。 九、AJAX与Fetch API 1. AJAX(Asynchronous JavaScript and XML)用于异步加载数据,通过XMLHttpRequest对象实现。 2. Fetch API:现代浏览器更推荐使用Fetch API,它提供了...

    JavaScript网页特效

    理解事件冒泡和事件捕获机制也很重要。 3. **CSS操作**:JavaScript可以直接修改元素的CSS样式,如`style.backgroundColor`改变背景色,`style.fontSize`调整字体大小,或者使用`getComputedStyle()`获取元素的实际...

Global site tag (gtag.js) - Google Analytics