#
事件使得客户端的 JavaScript 有机会被激活,并得以运行。在一个 Web 页面装载之后,运行脚本的唯一方式,就是响应系统或者用户的动作。虽然从第一个支持脚本编程的浏览器面世以来,简单的事件被实现为 JavaScript 的一部分;但是大多数最近出现的浏览器都实现了强壮的事件模型,使脚本可以更加智能地处理事件。现在的问题在于:为了支持各种浏览器,您必须和多个先进的事件模型做斗争,准确地说,是三个。
这三个事件模型分别和下面的文档对象模型(Document Object Model,即 DOM)三巨头结盟:Netscape Navigator 4 (NN4),Macintosh 和 Windows 系统的 Internet Explorer 4 及其更新版本(IE4+),以及在 Safari 中得到实现的 W3C DOM。尽管这些模型之间有些地方存在一些本质的差别,但是在一些简易的 JavaScript 的帮助下,它们都可以同时适用于同一个文档。本文主要着眼于相互冲突的事件模型中的两个关键方面:
1. 把一个事件和 HTML 元素绑定起来的方法。
2. 在事件被触发后如何对之进行处理。
事件绑定的方法1:绑定元素属性
事件绑定是指构造一个响应系统或者用户动作的 HTML 元素的过程。在不同的浏览器版本中,有不少于五种事件绑定技术。下面我们快速地介绍一下这些技术
最简单和向后兼容性最好的事件绑定方法是把事件绑定到元素标识的属性。事件属性名称由事件类型外加一个“on”前缀构成。尽管HTML属性并不是大小写敏感的,人们还是定义了一个规则,规定事件类型的每一个“词”的首字母大写,比如onClick 和onMouseOver。这些属性也被称为事件处理器,因为它们指示了元素如何“处理”特定的事件类型。
例子:
<INPUT TYPE="button" NAME="myButton" VALUE="Click Here" onClick="myFunc()" >
把事件绑定到元素属性上有一个优点,即可以支持开发者把参数传递给事件处理器函数。接收事件的元素的引用则由一个特殊的参数值--this
关键字来传递。下面的代码演示一个函数如何借助传入参数,把任意数目的文本框的内容转化为大写:
<SCRIPT LANGUAGE="JavaScript" >function convertToUpper(textbox) {
textbox.value = textbox.value.toUpperCase();}
</SCRIPT>... <FORM ....>
<INPUT TYPE="text" NAME="first_name" onChange="convertToUpper(this)" >
<INPUT TYPE="text" NAME="last_name" onChange="convertToUpper(this)" >... </FORM>
事件绑定的方法2:绑定对象属性
最简单和向后兼容性最好的事件绑定方法是把事件绑定到元素标识的属性。事件属性名称由事件类型外加一个“on”前缀构成。尽管HTML属性并不是大小写敏感的,人们还是定义了一个规则,规定事件类型的每一个“词”的首字母大写,比如onClick 和onMouseOver。这些属性也被称为事件处理器,因为它们指示了元素如何“处理”特定的事件类型。
把事件绑定到元素属性上有一个优点,即可以支持开发者把参数传递给事件处理器函数。接收事件的元素的引用则由一个特殊的参数值--this 关键字来传递。下面的代码演示一个函数如何借助传入参数,把任意数目的文本框的内容转化为大写:
<INPUT TYPE ="button" NAME ="myButton" ID ="button1" VALUE ="Click Here" >
脚本语句并不在函数中,而是在 <SCRIPT > 标识中,如下所示:
<SCRIPT FOR="button1" EVENT="onclick" > </SCRIPT >
事件绑定方法IV:使用 IE5/Windows 的 attachEvent() 方法
attachEvent() 方法的用法如下所示:elemObject.attachEvent("eventName", functionReference);eventName 参数的值是表示事件名称的字符串,比如 onmousedown。functionReference 参数是一个不带括号的函数引用,和早些时候描述的事件属性方法中一样。因此对于上面例子的按键对象,可以通过如下的脚本语句把函数绑定到按键的 click 事件:
document.getElementById("button1").attachEvent("onclick", myFunc);由于 attachEvent() 方法必须严格工作在 IE5+/Windows 的环境中,所以您既可以使用 W3C DOM 的元素引用方式(如上文所示),也可以使用 IE4+ 的引用方式:document.all.button1.attachEvent("onclick", myFunc);
事件绑定方法V:addEventListener() 方法
addEventListener() 方法的语法如下所示:nodeReference.addEventListener("eventType", listenerReference, captureFlag);用 W3C DOM 规范中的行话来说,addEventListener() 方法为指定的结点注册了一个事件,表示该结点希望处理相应的事件。这个方法的第一个参数是一个声明事件类型的字符串(不带"on"前缀),比如click,mousedown,和keypress。addEventListener() 方法的第二个参数可以和早些时候描述过的函数引用同样对待。
事件的信息矿:事件对象
事件对象通过提供足够的“挂钩”,使事件处理函数可以读取事件的特征,从而填补了这个缝隙。因此,事件处理函数可以得到接收事件的元素的引用,以及其它一些有用的信息,比如鼠标动作的坐标,鼠标使用的按键,键盘上被按压的键,以及在事件发生的过程中是否有修饰键被按下(比如检测 Shift-click 事件)。
访问事件对象
虽然事件对象的精确构成因为本文讨论的三种 DOM(NN4,IE4+,以及 W3C/Safari)的不同而有所变化,但是,一个事件处理函数只能通过以下两种方式之一来访问事件对象:NN 方式和 IE 方式。W3C/Safari DOM 事件对象公布给脚本的接口方式和 NN4 的事件对象一样;而 IE4+ 则有自己的方法。IE4+ 的事件对象更加易于描述,因此我们首先对它进行讨论。简单地说,事件对象是 window 对象的一个属性。这意味着在所有的实例中只有一个事件对象。举例来说,在键盘上简单地按压和松开一个按键,会产生三个事件:onKeyDown,onKeyPress,和 onKeyUp(事件的发生顺序和这里的列举顺序相同)。如果onKeyDown事 件激活的函数花费很长的时间进行处理,则浏览器就会把其它两个事件保持在队列中,直到onMouseDown 事件处理完成为止。而对于 NN4 和 W3C DOM 来说,事件对象看起来就更加抽象一些。除了基于标识属性风格的绑定方法之外,其它绑定方法都是把事件对象自动传递给与事件相绑定的函数。传递给函数的是一个单一的参数。开发者需要在函数中定义一个参数变量,来“接收”该参数的值。为了避免和IE中的window.event 对象互相冲突,请不要把参数命名为 event。举例来说,把它命名为evt 就相当好,相应的事件函数的定义大致如下:
function myFunc (evt) {
兼容两种事件对象引用
function myFunc(evt) { evt = (evt) ? evt : ((window .event ) ? window .event : "" )
function myFunc(evt) { evt = (evt) ? evt : ((window .event ) ? window .event : "" ) if (evt) {
一个事件处理函数的模板
1.并不是每个事件处理函数都处理页面元素对象中同样的属性或者行为,但是,从上文的讨论可以派生出来的一个模板,您可以在这个模板的帮助下开始编码。模板如下
function functionName(evt) { evt = (evt) ? evt : ((window .event ) ? window .event : "" ) if (evt) { var elem if (evt.target) { elem = (evt.target.nodeType == 3 ) ? evt.target.parentNode : evt.target } else { elem = evt.srcElement } if (elem) {
2. 请把第一行的函数名替换为您希望的函数名,并在注视指示的地方开始书写具体事件的代码。这个格式应该可以为您提供一个起点,适合于您采用的任何跨浏览器的事件绑定风格。如果您需要在一个页面中多次使用这个格式,则可以进一步精简代码,即把读取目标的代码抽象成一个可重用的工具函数,然后在每一个事件处理函数中进行调用:
// shared function function getTargetElement(evt) { var elem if (evt.target) { elem = (evt.target.nodeType == 3 ) ? evt.target.parentNode : evt.target } else { elem = evt.srcElement } return elem}function functionName(evt) { evt = (evt) ? evt : ((window .event) ? window .event : "" ) if (evt) { var elem = getTargetElement(evt) if (elem) { // process event here } }}