<一、事件>
事件(或者应该称之为事件类型)就是指当某种交互行为(如:用户操作、浏览器行为)发生时而导致文档内容需要做某些处理的场合。事件不是以on开头的那个名称,如onclick不是事件,而click才是事件,或者更准确的说就是“click事件类型”。onclick引用的是一个元素对象的属性,指向click事件类型所绑定的事件处理函数。
JavaScript是基于事件处理的程序,它响应操作是通过事件驱动的模式来实现的,事件驱动是面向对象程序设计中的一个核心概念,也称为设计模式。这种设计模式的核心就是“以消息为基础,以事件来驱动(message baseed,event driven)”。由于不同浏览器也在不断兼容模型,因此在开发时我们还应该考虑到浏览器不兼容性问题。目前主要存在以下四种事件处理模型:基本事件处理模型、标准事件处理模型、IE事件模型、Nerscape4.0事件模型,其中,最后一种模型由Nerscape4.0版本实现,但是在Nerscape6.0版本停止支持,转而开始支持标准模型,因此一般可以忽略不计这种模型。
JavaScript事件不支持多线程设计,有时可以使用setTimeout()函数来模拟并行处理各种任务,但是它仍然是单一线程行为。
<二、事件流>
事件流(Event Flow),就是事件发生的顺序,通俗的说,就是每个元素都按照特定的顺序响应指定的事件。事件流包含两层含义:
①事件的发生是有序响应的,而不是无序触发。即JavaScript事件总是从上到下或从下到上触发响应,并进行传播。
②在页面中,可以多个元素同时响应一个事件。流意味着多的意思,多个对象同时响应同一个事件,犹如流水一般。
所谓事件传播,就是事件在文档结构中能够进行传递。当事件发生时,除了目标结点能够捕获到事件外,目标结点的任何祖先都可以响应该事件,并调用事件处理函数。事件在传播过程中可以分为以下3个阶段:
①捕捉阶段:首先,事件从Document对象沿着DOM树向下传播到目标结点,如果目标元素的任何一个父结点注册了该事件,就有机会捕捉该事件,并调用事件处理函数
②目标阶段:事件传播的第二个阶段就是目标结点自身,注册在目标结点上的相应的事件处理函数就会被调用、执行。
③起泡阶段:最后事件从目标结点开始返回向上进行传播,如果父结点注册了相应事件处理函数,就会被调用执行。当然,并不是所有事件事件类型都有起泡阶段,例如,表单提交事件就只能够在当前元素身上响应,它不会身上起泡,传播给上级元素。
冒泡型事件流的基本思路是:事件流按照从最特定的事件目标(即最具体的事件绑定对象)到最不特定的事件目标(Document对象)的顺序触发,也就是说,事件从下到上传递,这个传递过程犹如冒水泡一样不断上升,所以形象的比喻为冒泡。但是对于不同类型或版本的浏览器来说,冒泡型事件流的具体约定也略有不同,具体比较如下:
①IE5.5及其以下版本:p→body→document
②IE6.0及其以上版本:p→body→html→document
③Mozilla1.0及其以上版本:p→body→html→document→window
捕获型事件流总是从最不精确的对象(Document对象)开始触发,然后到最精确的对象。即对象按从上到下的顺序响应。
<三、DOM2标准模型绑定和销毁事件>
在DOM2事件模型中,属性type获取事件的类型,属性target用来当前被激活事件的具体对象,即发生事件的结点。
DOM2级规范为所有元素对象定义了两个方法:addEventListener()和removeEventListener(),它们分别用来指定元素绑定和销毁事件类型。如果从字面上的意思理解,即增加事件监听函数和移除事件监听函数,也有人称之为注册和销毁事件处理函数。
addEventListener()方法包含3个参数,它的语法格式如下:addEventListener(String type,Function listener,boolean useCapture);
其中,type表示要绑定事件的类型名(注意事件类型click与事件属性onclick不同);listener表示回调函数,在指定类型的事件发生时调用这个函数,调用时,传递给它的唯一参数是Event对象;useCapture是一个布尔值,如果为true,则在事件传播的捕捉阶段触发响应,如果该参数为false,则在事件传播的冒泡阶段触发响应。
removeEventListener()方法和addEventListener()方法的用法一样,也有三个一样的参数。不过,在销毁事件时,要注意以下两个问题:
①通过函数引用的方式绑定事件,而不要直接使用匿名函数,因为这样FireFox浏览器会把绑定和注销中两个相同结构的匿名函数视为不同函数。
②第三个参数设置必须一致。如果使用addEventListener()方法将事件处理函数绑定到捕获阶段,则必须在removeEventListener()方法中指明捕获阶段,只有这样才能够正确删除事件处理函数。如果绑定在冒泡阶段的事件处理函数,而在捕获阶段来删除它,虽然这样做不会引发错误,但是销毁操作是无效的。
使用DOM2级事件模型的绑定方法有很多优点。该方法能够同时支持事件处理的捕获和冒泡阶段,也可以为同一个元素绑定多个事件,而且不会覆盖前面的事件。在该方法的事件处理函数的内部,this关键字总是引用当前元素。并且事件对象总是可以通过事件处理函数的第一个参数获取。
<四、IE事件模型绑定和销毁事件>
虽然标准事件模型非常好用,但IE浏览器不支持DOM的addEventListener()方法。
在IE事件模型中,属性type用来获取事件类型,属性srcElement用来获取发生事件的元素。
在IE浏览器中,每个元素和Window对象都包含两个方法:attachEvent()和detachEvent()。它们与DOM2事件模型的addEventListener()和removeEventListener()方法功能相同,但是,attachEvent()和detachEvent()方法不支持事件捕捉,所以它们的参数只有两个。
attachEvent()方法包含2个参数,它的语法格式是:attachEvent(String type,Function listener);
注意:此时应该要绑定事件处理函数的名称(如:onclick)
当没用detachEvent()方法时,不能够使用匿名函数,否则attachEvent()方法和detachEvent()方法包含的匿名函数将被视为不同的函数结构,因此无法真正删除。
为了能够兼容IE和标准这两种不同的事件类型,我们使用如下表达式来兼容:event = event || window.event;
其中右侧是一个选择运算,如果存在event参数,就使用event参数来传递事件信息;如果不存在event参数,则调用Window对象的event属性来获取事件信息,把上面的表达式放在事件处理函数中即可。
IE事件模型中的起泡与标准模型中的起泡区别就在于起泡方式不同,IE没有stopProgressive()方法,但是可以使用Event对象的cancleBubble属性进行设置:window.event.cancleBubble = true; 该属性设置只能够适用当前事件,新生的事件将被赋予默认的false。
——本文摘自:《jQuery开发完全宝典》