JavaScript Event事件学习第一章 Event介绍
作者:
没有event就没有脚本。可以看看任何有JavaScript代码的网页:几乎所有的例子都有一个事件触发了脚本。原因非常简单。JavaScript就是给你的页面添加内部活动:用户做一些事情然后页面做出回应。
因此JavaScript就需要一个方法能够检测到用户的动作然后才能知道什么时候做出反应。这还需要知道那个函数会被执行,函数会做一些你认为的给你的网页增色的动作。这些文字描述了如何去写这样的脚本。虽然不容易,但是这是一个很让人满足的工作。
当用户做了什么事情event就发生了,当然还有一些event不会直接被用户触发:比如load事件会在页面装载完毕的时候触发。
JavaScript能够检测一些event。从Netscape 2开始,在HTML元素上添加event hanlder就成为可能。这些事件处理函数等待一个确定的事件,比如点击一个链接。当他发生的时候,事件就会通过你指定的JavaScript代码来执行。
当用户做出动作他就引发了一个事件。当你的代码让页面对这个动作做出回应,交互就产生了。
事件处理程序的历史
如上所述,没有事件处理程序就没有在页面添加JavaScript的必要。那些能对用户动作做出反应的就是最好的脚本。因此,当Netscape发布他的第二版支持JavaScript的浏览器的时候,他同时也支持event。
Netscape模式
Netscape只支持一小部分事件。Mouseover和mouseout的快速流行时因为当鼠标滑入时改变图片而滑出时又返回到原来的状态这个很炫的效果。而且可以看到用户是否提交了表单或者重置了表单,这样在客户端的验证也就成为了可能。浏览器还能监测表单的某一项获得或者失去了焦点或者页面完成下载又或者开始关闭。在如今看来这些都是非常稀松平常的事情,但在那个时候那可是革命性的。因为你能对用户的动作做出反馈,所以真正的交互才变成可能。
在最古老的表单的事件处理程序看起来是这样的。当用户点击了链接,事件处理程序就被执行了然后弹出对话框。
<a href="somewhere.html" onclick="alert('I\'ve been clicked!')">
注意到这种最古老的处理事件的方法事实上就是Netscape的标准是很重要的。如果想要JavaScript工作,其他的浏览器包括IE都得遵从Netscape 2和3的处理事件的标准。因此这些最古老的事件和事件处理程序在任何JavaScript浏览器中都能很好的运行。
现在的事件模式
然而,相比之前的介绍,现在的事件处理程序有了很大的变化。第一就是数量上急剧增长。对HTML元素的事件处理程序的注册的方法也有很大的变化。现在完全可由JavaScript设置。不再需要大量的附着于代码之上,你可以写一些很简单的代码来设置所有的事件处理程序。
V4浏览器也提供了关于事件的很多信息。鼠标在哪?什么时候事件发生?键盘按下了么?最终,浏览器必须要对一个元素和这个元素的父元素对同一个动作都有事件处理程序做出选择。哪个事件先触发呢?
因为这个功能而更加加剧了浏览器之间的战火,Netscape和微软制订了几乎互不兼容的两套事件模型。最近第三种模型开始显现,这是由w3c发布的DOM Event specification 。虽然有一个严重的缺陷,w3c模型是基于旧的Netscape模型但是更加的广义和通用,这是一份非常杰出的作品,添加了很多有趣的函数,也解决了一些老的事件模型存在的问题。
既然存在三种模型,所以事件处理程序也就不能以同样的方式在所有的浏览器里面运行。
浏览器的兼容性问题
我们继续。就像DHTML,w3c DOM或者其他高级的脚本技术一样,我们对于代买的每一个字节都要小心。在IE中使用stopPropagation()或者在Netscape中使用srcElement都会导致严重的错误而使我们的代码毫无用处。因此在使用方法或者属性之前我们必须对浏览器的支持性做必要的检查。
一个简单的代码片段如下:
if (Netscape) {
use Netscape model
}
else if (Explorer) {
use Microsoft model
}
这只是解决问题的一个开始而已。最近的浏览器能运行的事件处理程序的数量是巨大的,除非你的代码不允许除了Netscape或者IE其他少数浏览器运行。
所有的小众浏览器都必须不那么光彩的决定支持那种事件模型。Konqueror/Safari通常都选择严格的按照W3C的标准执行。Opera和iCab通常都会支持大部分的老的Netscape模型和一些微软的模型。我对其他的更小众的浏览器还没有做研究。
但是其他的更小众的浏览器可能选择支持微软处理事件的方法,同时又有W3C和老的Netscape的属性。这都没什么问题,总之他们都是以他们自己的方法支持我们知道的模型。你的代码应该没有问题。
不要使用浏览器类型检测
首先,永远永远都不要使用浏览器检测,这是通向地狱的捷径。任何代码如果使用navigator.userAgent来做事件模型的检测,那简直比没用还没用应该直接拉出去弹JJ。
第二,不要被DHTML的object detection的事件对象检测所迷惑。当你写DHTML的时候通常检测DOM的支持性,比如,if(document.all)。如果支持,那么代码如果使用Microsot的all容器就能搞很好的运行。
但是DHTML和事件处理程序有不同的浏览器兼容性模式。比如,Opera 6支持W3C DOM的一部分但是不支持W3C event模型。因此DHTML对象检测在Opera下会做出错误的决定。所以代码使用if(document.layers)或者其他的事件模型检测都是不正确的。
正确的问题
那么我们怎么办?Event属性的名字造成了这些问题。如果我们针对具体的对象探测使用不同的办法,基本上能解决99%的浏览器的不兼容问题。只有鼠标位置非常的麻烦,其他的都比较简单了。
另外,最好根本就不要去想那三个事件模型。实际上,我们应该去理解四种事件注册模型,两种事件执行模型和两种事件顺序。 这里可以快速查看下事件兼容性列表。
现在听起来好像非常的复杂,实际上并不是这样。当我们注意到这个的时候也就应该开始真正的理解事件处理程序了。这都是关于如何提出正确的问题的。不要问“我该怎么写事件处理程序的代码呢?”即使这是一个正确的问题,但是难以回答--那需要11页长的文章才能说清楚。因此你应该问那些有具体答案的具体问题:
“这里都有什么事件?”
“我怎么对一个HTML元素注册事件处理程序呢?”
“我怎么阻止默认动作的发生呢?”
“当我想要得到更多的信息的时候我怎么访问一个事件呢?”
“当我成功的触发了事件,我怎么读取他的属性呢?”
“如果一个元素和他的父元素对一个事件都有事件处理程序,那么谁先执行呢?”
上面所有的问题都会在单独的章节进行详细的解答。
写跨浏览器的事件处理程序的的技巧在于不要用整体的事件模型而是分别的回答每一个问题。你会发现,你只有在需要读出事件属性的时候才需要考虑浏览器的兼容性问题。
先选择一个事件注册模型,然后确定这个事件会在所有的浏览器里面触发,然后读出正确的属性,最后解决事件触发顺序问题-如果有的话。这样你就能分贝的解决浏览器兼容性问题也能确保你的代码能在所有的浏览器里良好的运行。
继续
如果你想按照顺序学习事件,你应该开始读下一章了。
写事件处理程序的代码
那么怎样写事件处理程序的代码呢?为了希望快速得到答案和打算以后再学习理论的童鞋,在这一章我会做一个简单的概述。
注册一个事件处理程序
第一步是先注册你的事件处理程序。你需要确定的是浏览器会在任何时候都执行你的代码。
这里有四种注册事件处理程序的方法:inline,traditional,w3c和Microsoft。
最好使用traditinal方法,因为他能很好的跨浏览器并且有很大的自由和通用性。注册一个事件处理程序,如下:
element.onclick = doSomething;
if (element.captureEvents) element.captureEvents(Event.CLICK);
现在这个函数doSomething()就注册成为一个HTML的element元素click事件的事件处理程序。这意味着无论什么时候用户点击了这个元素,那么doSomething()都会执行。
访问这个事件
但你注册了你的事件处理程序你就开始写真正的代码了。通常你想访问这个事件本身,所以你可以读取这个事件的信息。
访问这个事件所以你可以读出他的属性,通常你的事件处理程序开始如下:
function doSomething(e) {
if (!e) var e = window.event
// e refers to the event
}
现在e就表示在所有浏览器里面的事件,你也可以访问这个事件。
访问这个HTML元素
有时候你希望能够访问到发生事件的元素。这里有两个办法:使用this关键字或者使用target/srcElement属性。
比较保险的访问HTML元素的方法是使用this关键字。this并不总是指向正确的HTML元素,但是和traditional模式一起就能很好的工作。
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元素的引用。非常有用,但是当事件被捕获或者冒泡了他依然是那个最初发生事件的元素不会改变。
读取属性
在读出一些有趣的事件属性(event properties)这个问题上,是浏览器兼容最不好的部分。学习这个兼容性列表,然后写出你自己的代码来获取你需要的信息。
确定总是使用最仔细的对象检查。首先确定每一个属性是否存在,然后再读取他的值。比如:
function doSomething(e) {
if (!e) var e = window.event
if (e.keyCode) code = e.keyCode;
else if (e.which) code = e.which;
}
现在code就包括了所按下的键,并且兼容所有的浏览器。
事件顺序
最后,你需要决定你是否希望事件冒泡。如果不希望发生事件冒泡,那么就阻止他:
function doSomething(e) {
if (!e) var e = window.event
// handle event
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
}
写代码
现在你可以开始写事件处理程序的代码了。通过前面的代码和信息,可以让你知道事件什么时候发生,你的代码应该做怎样的回应。记住:让交互更有逻辑性要么你的用户不会理解发生了什么。