js事件——Events

来源:互联网 发布:福州广电网络数字电视 编辑:程序博客网 时间:2024/06/06 05:41

没有共产党就没有新中国,没有 events 就没有 scripts。每个包含 JavaScript 的页面中: 几乎所有的脚本都是由 event 触发的。原因很简单。 JavaScript 可以增加交互性: user 做一些操作,页面给出响应。Events 是所有 JavaScript 应用的小心脏。本文介绍了事件处理机制,相关问题以及如何写出跨浏览器的 scripts。同时也展示了几个带有事件处理细节的页面。

因此JavaScript 检测用户的操作,以便知道何时做出反应,反应时执行哪个 functions 。

当用户做出某操作就会触发一个 event 。也有一些  events 不是由用户直接触发: 例如 load event 是页面加载时触发的。

JavaScript 可以检测一些 events。从 Netscape 2 开始就可以把事件处理程序( event handler)附加到某个HTML 元素。 事件处理程序会等候某个 event (例如 链接上的 click 事件 )发生。这时候就会执行你定义好的JavaScript 代码来处理事件 。

用户操作会产生一个 event。当 script 对 event做出响应,这就是所谓的交互。

事件处理的历史

假如没有事件处理机制,在页面中添加 JavaScript 就毫无意义。好的脚本可以对用户操作做出响应。因此网景发布第二版支持JavaScript的浏览器时,它也支持事件处理机制。

Netscape 模型

Netscape 2 只支持一些 events。Mouseover 和 mouseout 很快风靡,因为可以通过onMouseOver 改变  images ,通过onMouseOut 把它们变回去。在那个时候是很神奇的。也可以看到用户 submit  或 reset 表单,因此实现了客户端表单验证( form validation)。浏览器也可以检测表单获得焦点、失去焦点、页面加载完成、开始上传等。尽管现在看来很稀松平常,但是在那个年代,这可是Web页面革命性的进展。真正的交互成为了可能,因为你可以对用户操作做出响应。

最古老的事件处理就下面一样:

<a href="somewhere.html" onclick="alert('I\'ve been clicked!')">

这种最古老的事件处理机制实际上是由Netscape 定义的标准。如果想要JavaScript工作,其他的浏览器包括IE都得遵从Netscape 2和3的处理事件的标准。因此这些最古老的事件和事件处理程序在任何JavaScript浏览器中都能很好地运行。

现代事件模型

然而,自从引进这些简单的事件处理器后很多东西都发生了变化。首先事件数量增加,同时,事件注册机制也发生了变化。现在可以完全由JavaScript来设置。不再需要大量的附着于代码之上,你可以写一些很简单的代码来设置所有的事件处理程序。

第4版的浏览器还提供了更多的关于事件本身的信息。光标在哪儿(光标在撒钱)事件何时触发?有没有键被按? 如果该界面元素存在父子元素,而且父子元素也定义了同样的事件,这个时候事件该如何处理呢,事件在父子元素之间是如何传递的呢,谁会先接收到这个事件,又是谁先处理呢?不同的浏览器其处理机制也不尽相同。

在网景和微软斗争的年代,两个公司选择了完全不同的事件模型。W3C非常理智的处理了这种差异,在两者之间采取了中和的方法 DOM Event specification。除了一个严重漏洞( serious flaw), W3C的模型, 添加了很多新功能并解决了旧模型的很多问题。

三个模型意味着事件处理机制在不同的浏览器中可能有所不同。

浏览器兼容性问题

 就像 DHTML,W3C DOM 或其他的高级脚本技术一样,我们必须在浏览器中小心翼翼地执行代码。 在 Explorer 中调用 stopPropagation() 或者在 Netscape调用 srcElement 将会导致严重的错误甚至导致脚本不可用。因此在使用之前,我们必须确保浏览器支持该方法或该属性( the methods or properties) 。

如下一个简单的代码分支

if (Netscape) {use Netscape model}else if (Explorer) {use Microsoft model}

只是一个近似的解决方案,因为它忽略了非主流的浏览器。现在的解决方案可以处理大量的 modern event handling,除非你的脚本机智地设定非主流浏览器不允许执行代码,因为它们不是 Netscape 或 Explorer。

所有其他非主流的浏览器都必须做出决定站在哪一队:支持哪一种模型。Konqueror/Safari, 选择了严格的标准并支持 W3C model。Opera and iCab 则比较谨慎,支持旧的 Netscape model 和 Microsoft model中的大部分。

但非主流的浏览器可能支持的是 Microsoft 标准,但实际上其事件属性既有 W3C 的也有 old Netscape model的。

不要使用浏览器检测

首先,千万不用使用 browser detect。这是最快的作死方法。任何代码如果使用navigator.userAgent事件模型检测简直没用还没用应该直接拉出去弹JJ。

其次,不要将 DHTML 对象检测(object detection  )与事件对象检测混为一谈。当书写DHTML 时我们通常这样检测是否支持DOM: if (document.all) is supported. 如果是酱紫,使用 Microsoft allcontainer 的脚本可以正常执行。

但 DHTML和事件处理程序有不同的浏览器兼容模式。例如: Opera 6 支持部分 W3C DOM 但不支持 W3C event model。因此在Opera中。所以代码使用  if (document.layers) 或者其他的事件模型检测都是不正确的。

正确的提问

然后我们应该做些什么? 事件属性( event properties)引起严重的问题。如果我们使用大量特定对象检测,可以解决99%的浏览器的不兼容问题。只有鼠标位置( mouse position)非常的麻烦,其他的都比较简单了。

此外,最好是不去在意三个事件模型。相反,我们必须理解四个事件注册模型,两个事件访问模型和两个事件的命令。
事件处理和浏览器兼容性,参见事件兼容性表( event compatibility tables)。

貌似很复杂,其实so easy。实际上,当我认识到要对不同事件模型单独处理之后,我才开始真正理解事件处理。 这都是关于如何提出正确的问题的。别这么问“如何写一个事件来处理脚本?”  这是个问题,但很难给出答案,你应该问得再具体一点,别人才好给出答案:

  • “都有哪些事件?”
    很多,当然在某些浏览器中,一些事件无法生效。
  • “如何给一个HTML 元素注册事件处理程序?
    注册事件处理器有四种模型: 内敛模型( inline), 传统模型(traditional), W3C模型和微软模型(W3C and Microsoft)。第一种方法使用与所有浏览器,完全没有问题。
  • “如何阻止事件的默认行为?”
    从事件处理脚本中 return false , 默认的动作就会被阻止。该技术标准是由 Netscape 2 定义的,现在依然有效。
  • “若要获取更多事件相关的属性,该怎么做?”
    有两种方法:W3C 或 Netscape and Microsoft。为了解决这个问题你还需要这样一行代码。
  • “接下来改如何读取它的这些属性呢?”
    要读取这些属性存在兼容性问题,这些问题在事件属性这篇文章中详细说明了。要解决兼容性问题还需要参考事件属性兼容性表 和进行一些严格的对象检测。
  • “元素存在父元素,而且父元素也定义了同样的事件,这个时候事件该如何处理呢,事件在父子元素之间是如何传递的呢,谁会先接收到这个事件,又是谁先处理呢?” — 这个问题很有技术含量
    不同的浏览器有不同的方法。有两个 事件处理顺序,事件捕获(event capturing )和事件冒泡( event bubbling)。在实践中他们并不是很重要,只有少数情况下会用到,这种情况下我们通常会关心如何把它们关掉。需要两行代码。


写跨浏览器的脚本的技巧不是单单使用一个的事件模型,而是问自己上面那些问题。你将会发现需要考虑浏览器兼容性的情况:主要是在读取事件属性的时候。

首先选择一种事件注册模型, 确保所有的浏览器都支持该事件,随后去读取所需的事件属性,期间,如果存在兼容性问题的话还需要去解决。这样你就能浏览器兼容性问题各个击破,也能确保你的代码能在所有的浏览器里正常运行。

继续

如果你想详细了解事件相关的更加详细的内容,建议你继续阅读 events 这篇文章

编写事件处理脚本

如何编写呢?本文我给出了一个概述。

注册事件处理程序

第一步就是注册事件处理程序。但必须保证你选择的事件发生时浏览器会执行你的脚本。

注册事件处理器有四种模型:  内敛模型( inline), 传统模型(traditional), W3C模型和微软模型(W3C and Microsoft)。

最好的办法是使用传统模式,因为它是完全兼容的,并给出予很大的自由度和多样性。 注册事件处理程序,使用以下方法

element.onclick = doSomething;if (element.captureEvents) element.captureEvents(Event.CLICK);

现在函数 doSomething() 就被注册成为了HTML 元素element 的click 事件处理程序。一旦用户点击这个元素, doSomething() 就会被执行。

访问事件

注册了事件处理器之后就可以开始书写实际的脚本了。在通常情况下,你需要访问事件本身( access the event itself),这样就可以读取有关的事件信息。

通常事件处理程序都这样写:

function doSomething(e) {if (!e) var e = window.event// e refers to the event}

其中 e 指的是所有浏览器中可以访问的事件。

访问 HTML 元素

有时你也需要访问事件发生在其上的HTML元素。 有两种方法:使用this 关键字,或者使用 target/srcElement 属性。

访问 HTML 元素最稳妥的方法是使用this 。 this  并不能始终指向正确的 HTML 元素,但是结合传统模型可以良好地工作。

function doSomething(e) {if (!e) var e = window.event// e refers to the event// this refers to the HTML element which currently handles the event// target/srcElement refer to the HTML element the event originally took place on}

target/srcElement 属性包含了一个引用,指向事件最初发生的 HTML 元素。很有用,但是当事件被捕获或冒泡( is captured or bubbles up)的时候, target/srcElement 并不会随之改变:它仍指向事件最初发生的 HTML 元素。 target/srcElement 相关内容详见 Event properties 页面,this 关键字相关内容详见 this )

读取属性

读取事件属性( event properties)是浏览器兼容性的软肋。参考这个表格( event compatibility tables ) 来编写自己的脚本,读取想要的信息。

确保尽可能地使用最详细的对象检测。 首先检测每个属性是否存在,然后读取它的值。例如:

function doSomething(e) {if (!e) var e = window.eventif (e.keyCode) code = e.keyCode;else if (e.which) code = e.which;}

其中 code 表示浏览器中按下的按键。

事件顺序

最好,你要决定是否想让事件冒泡( bubble up)。如果不想让其发生,就阻止事件的传播:

function doSomething(e) {if (!e) var e = window.event// handle evente.cancelBubble = true;if (e.stopPropagation) e.stopPropagation();}

编写脚本

现在你可以开始正式写事件处理的脚本。利用上面那些代码片段得到的信息,来决定事件发生时到底发生了什么,以及你的脚本应如何应对。 

注意:时刻保持交互的逻辑思维,不然用户就麻爪了。


原文:Introduction to Events

0 0
原创粉丝点击