`

JavaScript Event学习:事件的顺序

 
阅读更多

基本问题很简单。假设你的一个元素包含在另外一个元素中。

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

这两个元素都有onclick事件处理程序。如果用户在element2上面单击那么在元素2和元素1上都触发了单击事件。但是哪个事件先发生呢?哪个事件处理程序会先执行呢?换句话说,事件顺序(event order)是什么呢?

  两种模式

  毫无疑问的,Netscape和微软在过去那段很糟糕的日子里都做出了自己的决定。

  Netscape说element1先发生的。这叫事件捕获(event capturing)。

  微软觉得element2先发生的。这叫事件冒泡(event bubbling)。

  这两种事件顺序刚好相反。IE只支持事件冒泡。Mozilla,Opera 7和Konqueror两种都支持。早一些的Opear和iCab浏览器两个都不支持。

  事件捕获

  当你使用事件捕获的时候

               | |
---------------| |-----------------
| element1     | |                |
|   -----------| |-----------     |
|   |element2  \ /          |     |
|   -------------------------     |
|        Event CAPTURING          |
-----------------------------------

element1的事件处理程序会先执行,element2后执行。

  事件冒泡

  当你使用事件冒泡的时候

               / \
---------------| |-----------------
| element1     | |                |
|   -----------| |-----------     |
|   |element2  | |          |     |
|   -------------------------     |
|        Event BUBBLING           |
-----------------------------------

element2的事件处理程序会先执行,element1的事件处理程序后执行。

  W3C模式

  W3C决定在这场战争中保持重力。在W3C事件模型中任何事件发生都是首先被捕获直到到达目标元素,然后再冒泡。

                 | |  / \
-----------------| |--| |-----------------
| element1       | |  | |                |
|   -------------| |--| |-----------     |
|   |element2    \ /  | |          |     |
|   --------------------------------     |
|        W3C event model                 |
------------------------------------------

作为设计师的你,可以随意选择把事件处理程序注册在捕获还是冒泡阶段。通过之前高级模式里面介绍的addEventListener()方法就可以完成。如果最后一个参数是true那么就设置成为事件捕获,如果是false就设置为事件冒泡。

  假设你这样写

 

element1.addEventListener('click',doSomething2,true)
element2.addEventListener('click',doSomething,false)
 如果用户在element2上单击就会发生下面的事情:

  1、click事件发生在捕获阶段。这样看来,如果element2的任何一个父元素有onclick事件处理程序那么都会执行。

  2、事件在element1上发现了doSomething2(),那么就会执行它。

  3、事件向下传递直到目标本身,再没有其他的捕获阶段程序了。事件转而进入冒泡阶段然后就会执行doSomething(),也就是element2注册在冒泡阶段的事件处理程序。

  4、事件再向上传递再检查是否有父元素在冒泡阶段设置事件处理程序。这里没有,所以什么也不会发生。

 

反过来:

 

element1.addEventListener('click',doSomething2,false)
element2.addEventListener('click',doSomething,false)
 现在如果用户在element2上面点击就会发生:

  1、事件click发生在捕获阶段。事件会查找element2的父元素是否有在捕获阶段注册事件处理程序,在这里没有。

  2、事件向下传递直到目标本身。然后开始冒泡阶段,执行dosomething(),这个是注册在element2冒泡阶段的事件处理程序。

  3、事件继续向上传递然后检查是否有父元素在冒泡阶段注册了事件处理程序。

  4、事件发现了element1.然后doSomething2()就被执行了。

  传统模式下的兼容性

  对于那些支持W3C DOM的浏览器来说,传统的事件注册

 

element1.onclick = doSomething2;
 就被看做是注册在冒泡阶段的。

  事件冒泡的使用

  很少有设计师意识到事件捕获或者冒泡。在网页制作的今天,貌似没必要让一个冒泡事件被一系列的事件处理程序来处理。用户也会在单击之后发生一系列事件而感到迷惑,通常你也想让你的事件处理程序的代码保持一定的独立性。当用户点击一个元素,发生了一些事情,当他单击其他元素,那么其他再发生其他事情。

  当然在将来也许会改变,最好让模式向前兼容。但是如今最实用的事件捕获和冒泡就是默认函数的注册。

  它总是会发生

  首先你需要理解的就是事件捕获或者冒泡总是在发生的。如果你为你的整个页面定义了一个onclick事件:

 

document.onclick = doSomething;
if (document.captureEvents) document.captureEvents(Event.CLICK);
你在任意元素上的click时间都会冒泡到页面然后出发了这个事件处理程序。只有当前面的事件处理程序明确的阻止冒泡,才不会传递到整个页面。

  使用

  因为每个事件都会在整个文档上停止,默认的事件处理程序就变得可能。假设你有一个这样的页面:

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

element1.onclick = doSomething;
element2.onclick = doSomething;
document.onclick = defaultFunction;
 

现在如果用户点击了element1或者element2那么doSomething()就会执行。在这如果你愿意也可以阻止他的传播。如果不的话,那么defaultFunction()就会执行。用户在其他地方的点击也会让defaultFunction()执行。有时候这可能有用。

  设置全局的事件处理程序在写拖动代码的时候就很有必要。通常一个层上的mousedow事件会选择这个层然后对mousemove事件做出回应。虽然 mousedown通常注册在这个层上来避免一些浏览器的bug,但是其他的事件处理程序都必须是全局的(document-wide)。

  记住浏览器逻辑的第一定律:什么都会发生的,而且经常是在你做的准备最少的时候。可能发生的是用户的鼠标疯狂的移动然后代码没有跟上导致鼠标已经不再这个层上了。

  * 如果在某个层上注册了onmousemove事件处理程序,如果这个层不再响应鼠标的移动了,那么肯定会让用户感到迷惑。

  * 如果某个曾上注册了onmouseup事件处理程序,那么程序会在用户松开鼠标的时候程序没有捕捉到造成这个层还在随着鼠标移动。

  在这种情况下事件冒泡就很重要,因为全局的事件处理程序会保证执行的。

  关掉它

  但是通常你想关闭所有的相关的捕获和冒泡。另外,如果你的文档结构非常的复杂(比如一大堆复杂的表格之类)你也需要关闭冒泡来节省系统资源。要不然浏览器就得一个个的查看父元素是否有事件处理程序。虽然可能一个都没有,但是查找一样浪费时间。

  在微软模式里你必须讲事件的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的浏览器里面设置也不会有啥问题。浏览器会创建一个这样的属性。当然是没啥用的,只是为了安全。

  currentTarget

  我们之前讲过,一个事件包含target或者srcElement包含一个发生事件的元素的引用。在我们的例子是element2,因为用户点击了他。

  理解在捕获和冒泡过程中这个target是不会改变的非常重要:他一直指向element2.

  但是假设我们注册了下面的事件处理程序:

 

element1.onclick = doSomething;
element2.onclick = doSomething;
 如果用户点击element2那么doSomething()执行了两次。那么你怎样知道那个HTML元素处理着这个事件呢?target/scrElement也不能给出答案,从事件一开始就一直指向element2.

  为了解决这个问题W3C添加了currentTarget属性。它包含一个正在处理的事件的HTML元素的引用:就是我们想要的那个。不幸的是微软模式没有类似的属性。

  你也可以用this关键字。在这个例子里就是指向正在处理的事件的HTML元素,就先currentTarget。

  微软模式的问题

  但是当你使用微软的事件注册模型,this关键字不是只想HTML元素的。然后又没有一个像currentTarget类似的属性,这就意味着如果你这么做:

 

element1.attachEvent('onclick',doSomething)
element2.attachEvent('onclick',doSomething)
 你就不知道那个HTML元素正在处理事件。这是微软的事件注册模式最严重的问题所以就根本不要用他,即使是那些只在IE/win下的程序。

  我希望微软能够尽快添加一个类似currentTarget的属性或者遵循标准?我们设计急需啊。

 

[转自:http://tech.ddvip.com/2010-03/1269927862148963.html]

分享到:
评论

相关推荐

    JavaScript Event学习第八章 事件的顺序

    本章主要探讨了两种主要的事件顺序模式:事件捕获和事件冒泡。 事件捕获是Netscape提出的模式,在这种模式下,事件首先从最外层的父元素开始,沿着DOM树向下传递,直到到达触发事件的元素。这意味着如果元素1包含...

    JavaScript的事件操作

    1. 事件:事件是用户或浏览器执行的特定动作,例如鼠标点击(click)、页面加载(load)或键盘按键(keydown)。 2. 事件处理:当事件发生时,JavaScript会调用相应的事件处理程序(handler)。事件处理程序可以是...

    Javascript Event Handlers.zip

    JavaScript事件处理器是JavaScript编程中的核心概念,用于处理用户与网页之间的...理解事件模型、各种事件处理器的绑定方式、事件处理顺序以及如何优化事件处理,对于提升用户体验和编写高效JavaScript代码至关重要。

    EventLoop执行顺序.zip

    在JavaScript的世界里,EventLoop(事件循环)是一个至关重要的概念,它确保了代码的非阻塞执行和异步处理。本文将深入探讨EventLoop的工作原理、执行顺序以及相关的宏任务和微任务。 首先,理解EventLoop的核心是...

    【JavaScript源代码】javascript事件冒泡,事件捕获和事件委托详解.docx

    5. **总结**:事件冒泡和事件捕获是JavaScript事件模型的两个阶段,它们定义了事件如何在DOM树中传播。事件委托则是一种高效利用事件处理的策略,可以降低内存消耗,提高性能,尤其适用于动态添加或删除DOM元素的...

    bigevent:大事件

    "bigevent:大事件"可能指的是一个JavaScript项目或者库,专门处理Web应用程序中的大型或复杂事件管理。在JavaScript中,事件处理是用户与网页交互的关键机制,如点击按钮、提交表单或者滚动页面等。 在JavaScript...

    JavaScript Event学习第九章 鼠标事件

    JavaScript中的鼠标事件包括了多个不同类型的事件,如mousedown、mouseup、click、dblclick、mousemove、mouseover和mouseout等,这些事件的熟悉和应用对于开发交互性网站界面至关重要。 在第九章中,作者首先介绍...

    JavaScript运行机制之事件循环(Event Loop)详解

    在深入探讨JavaScript的事件循环(Event Loop)之前,我们首先要明白JavaScript为何采用单线程模型。单线程模型意味着在任何时刻,JavaScript都只能处理一件事情,这与它的主要用途息息相关。JavaScript的使命是在...

    使用JavaScript事件综合查询,js事件大全

    在DOM2级事件模型中,可以设置`useCapture`参数决定事件处理顺序。 五、事件对象 每个事件触发时都会创建一个事件对象,其中包含了关于事件的信息,如事件类型、目标元素、鼠标位置等。在事件处理程序中,这个对象...

    JavaScript Event学习第五章 高级事件注册模型

    在JavaScript Event学习第五章中,主要探讨了两种高级事件注册模型:W3C模型和微软模型。这两种模型都是为了解决早期Netscape事件处理方式的问题,即无法绑定多个事件处理函数。 **W3C模型** W3C DOM层面的事件规范...

    base-event-dispatcher:事件调度程序项目的基类

    6. **事件阻止与默认行为**:事件处理函数可以调用`event.preventDefault()`阻止事件的默认行为,例如阻止链接的跳转或表单的提交。基类可能提供了简便的方法来实现这一功能。 7. **可复用的事件系统**:作为基类,...

    (word完整版)javascript看qq中多事件绑定的执行顺序.doc

    本篇文章将深入探讨JavaScript在不同浏览器环境下,尤其是IE浏览器中,如何处理多事件绑定的执行顺序。 在W3C的标准下,推荐使用`addEventListener`方法来绑定事件,它的特点是事件处理函数按照添加的顺序依次执行...

    JavaScript Event事件学习第一章 Event介绍

    当事件发生时,浏览器会按照一定的顺序触发事件处理程序,这可能导致父元素和子元素上的事件处理程序同时被触发。在事件冒泡中,事件会从最深的节点开始,然后逐级向上传播到根节点;而在事件捕获中,事件会从根节点...

    Event Based Programming

    1. **响应性**:事件驱动编程使得程序能够快速响应用户的输入或其他外部事件,提高用户体验。 2. **非阻塞性**:通过避免长时间运行的同步操作,事件驱动编程能够更好地利用计算资源,减少等待时间。 3. **可...

    浅析javascript中的Event事件

    JavaScript中的Event事件是Web开发中不可或缺的一部分,它用于处理用户与网页交互时产生的各种行为。在JavaScript中,事件处理主要涉及焦点管理、事件对象、事件流、事件绑定、事件取消绑定以及键盘事件和默认事件等...

    Javascript Event(事件)的传播与冒泡

    JavaScript中的事件传播与冒泡是理解DOM交互时的关键概念,主要涉及到事件的处理方式和执行顺序。事件传播是指当一个事件(如点击)在DOM树中发生时,它会从最深的节点(事件的目标节点)开始,逐级向上层节点传播。...

    eventbug:Firebug 扩展 - Firebug 的事件视图

    在使用`Eventbug`时,开发者可以查看各个元素上绑定的事件处理程序,了解它们的触发顺序和执行上下文。这对于定位问题、优化性能或者理解代码逻辑来说非常有帮助。例如,如果一个按钮的点击事件被意外触发多次,`...

    javascript的三种事件模型.docx

    JavaScript 事件模型是网页交互的核心机制,允许JavaScript代码在特定的用户操作或系统事件发生时执行。本文主要探讨了JavaScript中的三种事件模型,这些模型与不同的浏览器和DOM版本有关。尽管存在差异,但通过一些...

    【JavaScript源代码】JavaScript中事件冒泡机制示例详析.docx

    事件流主要有三种阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。 事件捕获阶段是从DOM树的根节点开始,沿着树向下传播到目标节点。在这个阶段,事件首先由最外层的父元素接收,然后逐级向下传递,直到到达触发...

Global site tag (gtag.js) - Google Analytics