The World of TomasRan

浏览器事件机制的几个基本概念

没有事件,网页玩不转

操作一个网页的时候,你的举手投足,一颦一笑时刻都被一个神秘人默默地关注着,你不用感到害怕,他不是一个坏银,恰恰相反,你想要前往的去处,达到的目标,他都会赶在你的前面先去铺路叠桥,不让你遭遇一点儿坎坷。他对于你的需求的重视已经远远超过了对自己生命的爱护,因此他会常常疲惫不堪,心力交瘁,有时甚至临近崩溃的边缘。但只要病魔不夺走他的意识,他都会为了你的需要而奔波忙碌。说着说着,我的眼角不禁为他绽放了感动的泪花。

这个似暗实明的神秘人,就是我们可亲可爱的web浏览器。

浏览器向我们展现了各色各样的网页,包含大量的交互动作,表单的提交,按钮的点击,窗口的滚动,等等等等。我们不能通过人类的语言和他沟通,让他完成某项工作,因此有了事件机制,构建人机沟通的桥梁。可以说在任何一个图形化界面的应用程序中,乃至图形化操作系统,都是事件响应机制来完成用户希望达到的目的或者期待显示的效果。

简而言之,在网页中,事件就是告诉浏览器发生了什么事情。浏览器以此为据,给予响应(事件是客户端的一种处理机制,虽然以下以Javascript语言为例,但是并不代表事件机制与Javascript这门语言存在直接联系,联系的建立是依靠客户端来实现的,事件机制本身并不是Javascript语言的内容)。

浏览器端的事件的处理是执行一段Javascript代码,浏览器端的交互模式的实现实际上是基于javascript的异步事件驱动模型编程。下面是该模型的简单图示:

想要了解javascript机制的全貌吗?我们先从它的基本组成部分说起。

事件类型

命名是一件严肃的事儿。在文学上,望文生义是大忌,而在编程界,我们在命名时就应该做到望文生义(这真的是一种良好的编码规范,足以让你感恩先辈遗福后来,你若傲娇我也没辙)。事件类型的命名,更应该如此,从看上去就应该知道这个事件类型对应了什么样的操作,而不致使人疑惑。

在Javascript中,定义了一系列具有实际意义的事件类型,比如“click”,定义了单击的事件(注意并不是只针对鼠标单击);“mouseover”,定义了鼠标移动到某一元素上的事件;“mouseout”,定义了鼠标移出某一元素的事件;等等。

它们中的每一种都代表了一种不同的操作或者状态。但是兼容性参差不齐,毕竟因为浏览器厂商的复杂局面,我们在面对不同浏览器以及它们的不同版本的时候,使用什么样的事件类型还是得多做考量。你也不用紧张,大多数已经列入标准的常用的事件类型都可以放心的使用。

这里不去列举每一种事件类型及其含义,具体可以参见 事件类型一览表

在事件类型的划分上,除了细到每一种具体的含义之外,从高一点的层次划分,一般可以分为:鼠标事件、键盘事件、触摸屏和移动端设备事件,window事件,dom事件和表单事件等。

事件目标

事件目标是发生事件的对象或者是与该事件相关的对象。

确定了事件类型,我们知道需要响应什么样的事件。但是,网页元素那么多,让每一个元素都响应该事件显然是不合理的。既然如此,我们就需要确定响应事件的目标。它可以是一个button,一个div,一个input框,或者整个文档,事件目标的确定自然依赖于需求。

事件处理程序

事件处理程序是事件目标在响应指定的事件类型时需要执行的程序。看看如下代码:

xxx.onclick = function(e) {
e = e || window.event;
e.target = e.target || e.srcElement;
...
}

后面的function声明的函数就是我们的事件处理程序。我们经常会看到以上函数声明,前两句和具体的业务逻辑并没有什么联系,它们的作用是为了解决浏览器兼容性问题。如果要探究其意义的话,我们自然要先弄清楚事件处理函数中传入的参数‘e’代表什么。

注意,这不是error的简写!而是事件对象。

事件对象

事件对象是什么?事件对象是与特定信息相关并且包含有关该事件详细信息的对象。

什么时候产生?当事件触发时生成,并传递给相应的事件处理函数。

什么时候销毁?当事件处理函数执行完立即销毁。

事件对象包含很多的属性,例如触发这个事件的事件目标 ‘target’,事件的类型 ‘type’ 等等,想要了解事件对象的具体属性可以参见 W3C Event对象

一般情况下,事件对象都会传递给事件处理函数,但总有浏览器别出心裁,例如IE8及其之前版本,它们不会在事件触发时生成一个单独的事件对象传递给事件处理函数,取而代之,它们采用了全局变量的方法,通过绑定在Window对象上的全局变量event来访问事件对象的属性,并且只有在事件处理函数执行的时候才能访问到这个对象,也就是说,window.event在一般情况下是访问不到的(看上去是事件处理函数执行时给全局变量添加了event属性,执行完之后删除,未研究源码,臆测)。因此为了解决浏览器兼容性的问题,就有了上文中的这一段代码:

e = e || window.event

事实上,IE中的event对象和其他浏览器的事件对象还有很多的属性差别。例如IE的event对象就没有target这一属性,而它的srcElement与其拥有同样的属性值。这样,也就催生出上文中的第二段代码:

e.target = e.target || e.srcElement

小结

以上是Javascript事件机制中的几个基本的概念,到目前为止,我们并没有为它们建立彼此之间的联系,先混个脸熟,之后再介绍具体的运作机制。