JS第十三章

148 阅读33分钟

JavaScript第十三章——事件

事件流

IE的事件流是事件冒泡流,而 Netscape Communicator的事件流是事件捕获流

IE的事件流:事件冒泡

事件开始时由具体的元素(文档中嵌套层次深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)

IE5.5 及更早版本中的事件冒 泡会跳过元素(从直接跳到 document)。IE9、Firefox、Chrome和 Safari则将事件一直 冒泡到 window 对象

事件捕获

事件捕获的思想 是不太具体的节点应该更早接收到事件,而具体的节点应该后接收到事件

用意在于在 事件到达预定目标之前捕获它

DOM事件流

三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段

IE9、Opera、Firefox、Chrome和 Safari都支持 DOM事件流;IE8及更早版本不 支持 DOM事件流。

事件处理程序

响应某个事件的函数就叫做事件处理程序(或事件侦听器)

事件处理程序的名字以"on"开头

HTML事件处理程序

某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的 HTML 特性来指定

注意:不能在其中使用未经转义的 HTML语法字符, 例如和号(&)、双引号("")、小于号(<)或大于号(>)

在 HTML 中定义的事件处理程序可以包含要执行的具体动作,也可以调用在页面其他地方定义的 脚本

使用 with 可以扩展作用域

指定事件处理程序的缺点
时差问题

用户可能会在 HTML元素一出现在页面上就触发相应的事件,但当时的事件处理程序有可能尚不具备执行条件

将其封装在一个 try-catch 块中,以便错误不会浮出水面

扩展事件处理程序的作用域链在不同浏览器中会导致不同结果

不同 JavaScript 引擎遵循的标识符解析规则略有差异,很可能会在访问非限定对象成员时出错

HTML与 JavaScript代码紧密耦合

要更换事件处理程序,就要改动两个地方:HTML代码和 JavaScript代码####

DOM0级事件处理程序

通过 JavaScript指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性

每个元素(包括 window 和 document)都有自己的事件处理程序属性,这些属性通常全部小写;将这种属性的值设置为一个函数,就可以指定事件处理程序

如果这些代码在页面中位于按钮后面,就有可能在一段时间内怎么单击都没有反应

使用 DOM0 级方法指定的事件处理程序被认为是元素的方法。因此,这时候的事件处理程序是在 元素的作用域中运行

删除通过 DOM0 级方法指定的事件处理程序

例子:btn.onclick = null; //删除事件处理程序

如果你使用 HTML指定事件处理程序,那么 onclick 属性的值就是一个包含着 在同名 HTML特性中指定的代码的函数。而将相应的属性设置为 null,也可以删除以这种方式指定的事件处理程序

DOM2级事件处理程序

定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener() 和 removeEventListener()

接受 3个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值

布尔值参数如果是 true,表示在捕获阶段调用事件处理程序;如果是 false,表示在冒泡阶段调用事件处理程序

使用 DOM2 级方法添加事件处理程序的主要好处是可以添加多个事件处理程序

通过 addEventListener()添加的事件处理程序只能使用 removeEventListener()来移除;移 除时传入的参数与添加处理程序时使用的参数相同

意味着通过 addEventListener()添加的匿名(无函数名)函数将无法移除

IE事件处理程序

IE实现了与 DOM中类似的两个方法:attachEvent()和 detachEvent()

接受相同的两个参数:事件处理程序名称与事件处理程序函数

使用 attachEvent()为按钮添加一个事件处理程序

在 IE 中使用 attachEvent()与使用 DOM0 级方法的主要区别在于事件处理程序的作用域。在使 用 DOM0级方法的情况下,事件处理程序会在其所属元素的作用域内运行;在使用 attachEvent()方 法的情况下,事件处理程序会在全局作用域中运行,因此 this 等于 window

与 DOM 方法不同的是,事件处理程序不是以添加它们的顺序执行,而是以相反的顺序被触发

使用 attachEvent()添加的事件可以通过 detachEvent()来移除,条件是必须提供相同的参数。 意味着添加的匿名函数将不能被移除,不过,只要能够将对相同函数的引用传 给 detachEvent(),就可以移除相应的事件处理程序

跨浏览器的事件处理程序

第一个要创建的方法是 addHandler(),它的职责是视情况分别使用 DOM0 级方法、DOM2 级方 法或 IE方法来添加事件,这个方法属于一个名叫 EventUtil 的对象

addHandler()方法接受 3个参数:要操作的元素、事件名称和事件处理程序函数

相对立的方法是removeHandler()

接受相同的参数。这个方法的职责是移除之前添加的事件处理程序

EventUtil 的用法

这两个方法首先都会检测传入的元素中是否存在 DOM2级方法。如果存在 DOM2级方法,则使用 该方法:传入事件类型、事件处理程序函数和第三个参数 false(表示冒泡阶段)。如果存在的是 IE的 方法,则采取第二种方案;为了在 IE8及更早版本中运行,此时的事件类型必须加上"on"前缀。 后一种可能就是使用 DOM0级方法

注意:DOM0 级对每个事件只支持一 个事件处理程序

事件对象

在触发 DOM上的某个事件时,会产生一个事件对象 event,这个对象中包含着所有与事件有关的 信息。包括导致事件的元素、事件的类型以及其他与特定事件相关的信息

DOM中的事件对象

兼容 DOM的浏览器会将一个 event 对象传入到事件处理程序中。无论指定事件处理程序时使用什 么方法(DOM0级或 DOM2级),都会传入 event 对象

event 对象包含与创建它的特定事件有关的属性和方法

在事件处理程序内部,对象 this 始终等于 currentTarget 的值,而 target 则只包含事件的实 际目标。如果直接将事件处理程序指定给了目标元素,则 this、currentTarget 和 target 包含相同的值

在需要通过一个函数处理多个事件时,可以使用 type 属性

要阻止特定事件的默认行为,可以使用 preventDefault()方法

stopPropagation()方法用于立即停止事件在 DOM 层次中的传播,即取消进一步的事件 捕获或冒泡

事件对象的 eventPhase 属性,可以用来确定事件当前正位于事件流的哪个阶段

如果是在捕获阶 段调用的事件处理程序,那么 eventPhase 等于 1;如果事件处理程序处于目标对象上,则 event- Phase 等于 2;如果是在冒泡阶段调用的事件处理程序,eventPhase 等于 3

注意:尽管 “处于目标”发生在冒泡阶段,但 eventPhase 仍然一直等于 2

只有在事件处理程序执行期间,event 对象才会存在;一旦事件处理程序执行完 成,event 对象就会被销毁

IE中的事件对象

在使用 DOM0级方法添加事件处理程序时,event 对象作为 window 对象的一个 属性存在。

使用 attachEvent()的情况下,可以通过 window 对象来访问 event 对象,就像使用 DOM0级方法时一样

如果是通过HTML特性指定的事件处理程序,可以通过一个名叫event的变量来访问event 对象(与 DOM中的事件模型相同)

IE的 event 对象包含与创建它的事件相关的属性和方法

returnValue与DOM 不同的是,在此没有办法确定事件是否能被取消

cancelBubble 属性与 DOM中的 stopPropagation()方法作用相同,都是用来停止事 件冒泡的。由于 IE不支持事件捕获,因而只能取消事件冒泡;但 stopPropagatioin()可以同时取消 事件捕获和冒泡

跨浏览器的事件对象

虽然 DOM和 IE中的 event 对象不同,但基于它们之间的相似性依旧可以拿出跨浏览器的方案来

getEvent(),它返回对 event 对象的引用。考虑到 IE中事件对象的位置不同,可以使用这个方法来取得 event 对象,而不必担心指 定事件处理程序的方式

getTarget(),它返回事件的目标。在这个方法内部,会检测 event 对象的 target 属性,如果存在则返回该属性的值;否则,返回 srcElement 属性的值

preventDefault(),用于取消事件的默认行为。在传入 event 对象后,这个方法 会检查是否存在 preventDefault()方法,如果存在则调用该方法。如果 preventDefault()方法不 存在,则将 returnValue 设置为 false

stopPropagation(),其实现方式类似。首先尝试使用 DOM方法阻止事件流,否 则就使用 cancelBubble 属性

事件类型

UI事件

UI事件指的是那些不一定与用户操作有关的事件

除了DOMActivate 之外,其他事件在DOM2级事件中都归为HTML事件(DOMActivate 在DOM2 级中仍然属于 UI事件)

  1. 确定浏览器是否支持 DOM2级事件规定的 HTML事件

var isSupported = document.implementation.hasFeature("HTMLEvents", "2.0");

注意,只有根据“DOM2 级事件”实现这些事件的浏览器才会返回 true。而以非标准方式支持 这 些事件的浏览器则会返回 false

  1. 确定浏览器是否支持“DOM3级事件”定义的事件

var isSupported = document.implementation.hasFeature("UIEvent", "3.0");

load 事件

定义 onload 事件处理程序的方法

这个 event 对象中不包 含有关这个事件的任何附加信息,但在兼容 DOM 的浏览器中,event.target 属性的值会被设置为 document,而 IE并不会为这个事件设置 srcElement 属性

指定 onload 事件处理程序的方式是为<body>元素添加一个 onload 特性

一般来说,在 window 上面发生的任何事件都可以在<body>元素中通过相应的特性来指定,因为 在 HTML中无法访问 window 元素

根据“DOM2级事件”规范,应该在 document 而非 window 上面触发 load 事 件。但是,所有浏览器都在 window 上面实现了该事件,以确保向后兼容

unload 事件

这个事件在文档被完全卸载后触发。只要用户从一个页面切 换到另一个页面,就会发生 unload 事件。而利用这个事件多的情况是清除引用,以避免内存泄漏

两种指定 onunload 事件处理程序的方式

使用 JavaScript:

为<body>元素添加一个特性(与 load 事件相似)

根据“DOM2级事件”,应该在元素而非 window 对象上面触发 unload 事件。不过,所有浏览器都在 window 上实现了 unload 事件,以确保向后兼容。

resize 事件

当浏览器窗口被调整到一个新的高度或宽度时,就会触发 resize 事件

与其他发生在 window 上的事件类似,在兼容 DOM的浏览器中,传入事件处理程序中的 event 对 象有一个 target 属性,值为 document

IE、Safari、Chrome和 Opera会在浏览 器窗口变化了 1像素时就触发 resize 事件,然后随着变化不断重复触发。Firefox则只会在用户停止调 整窗口大小时才会触发 resize 事件

浏览器窗口小化或大化时也会触发 resize 事件

scroll 事件

虽然 scroll 事件是在 window 对象上发生的,但它实际表示的则是页面中相应元素的变化

。在混 杂模式下,可以通过元素的 scrollLeft 和 scrollTop 来监控到这一变化;而在标准模式下, 除 Safari 之外的所有浏览器都会通过元素来反映这一变化

与 resize 事件类似,scroll 事件也会在文档被滚动期间重复被触发

焦点事件

焦点事件会在页面元素获得或失去焦点时触发。利用这些事件并与 document.hasFocus()方法及 document.activeElement 属性配合,可以知晓用户在页面上的行踪

当焦点从页面中的一个元素移动到另一个元素

blur、DOMFocusOut 和 focusout 的事件目标是失去焦点的元素;而 focus、DOMFocusIn 和 focusin 的事件目标是获得焦点的元素

确定浏览器是否支持这些事件

var isSupported = document.implementation.hasFeature("FocusEvent", "3.0");

即使 focus 和 blur 不冒泡,也可以在捕获阶段侦听到它们。

鼠标与滚轮事件

页面上的所有元素都支持鼠标事件。除了 mouseenter 和 mouseleave,所有鼠标事件都会冒泡, 也可以被取消,而取消鼠标事件将会影响浏览器的默认行为。取消鼠标事件的默认行为还会影响其他事 件,因为鼠标事件与其他事件是密不可分的关系

只有在同一个元素上相继触发 mousedown 和 mouseup 事件,才会触发 click 事件;如果 mousedown 或 mouseup 中的一个被取消,就不会触发 click 事件;类似地,只有触发两次 click 事 件,才会触发一次dblclick事件。如果有代码阻止了连续两次触发click事件(可能是直接取消click 事件,也可能通过取消 mousedown 或 mouseup 间接实现),那么就不会触发 dblclick 事件了

客户区坐标位置

鼠标事件都是在浏览器视口中的特定位置上发生的。这个位置信息保存在事件对象的 clientX 和 clientY 属性中。

页面坐标位置

通过客户区坐标能够知道鼠标是在视口中什么位置发生的,而页面坐标通过事件对象的 pageX 和 pageY 属性,能告诉你事件是在页面中的什么位置发生的

IE8 及更早版本不支持事件对象上的页面坐标,不过使用客户区坐标和滚动信息可以计算出来。这 时候需要用到 document.body(混杂模式)或 document.documentElement(标准模式)中的 scrollLeft 和 scrollTop 属性

屏幕坐标位置

鼠标事件发生时,不仅会有相对于浏览器窗口的位置,还有一个相对于整个电脑屏幕的位置。而通 过 screenX 和 screenY 属性就可以确定鼠标事件发生时鼠标指针相对于整个屏幕的坐标信息

修改键

修改键就是 Shift、Ctrl、Alt和 Meta(在 Windows键盘中是 Windows键,在苹果机中 是 Cmd 键),它们经常被用来修改鼠标事件的行为

DOM 规定了 4 个属性,表示这些修改键的状 态:shiftKey、ctrlKey、altKey 和 metaKey。这些属性中包含的都是布尔值,如果相应的键被按 下了,则值为 true,否则值为 false。

IE9、Firefox、Safari、Chrome和 Opera都支持这 4个键。IE8及之前版本不支持 metaKey 属性。

相关元素

在发生 mouseover 和 mouserout 事件时,还会涉及更多的元素

对 mouseover 事件而言,事件的主目标是获得光标的元素,而相关元素就是那个失去光标的元素

对 mouseout 事件而言,事件的主目标是失去光标的元素,而相关元素则是获得光标的元素

DOM通过 event 对象的 relatedTarget 属性提供了相关元素的信息。这个属性只对于 mouseover 和mouseout事件才包含值;对于其他事件,这个属性的值是null

在 mouseover 事件触发时,IE的 fromElement 属性中保 存了相关元素;在 mouseout 事件触发时,IE的 toElement 属性中保存着相关元素。(IE9支持所有这些 属性

鼠标按钮

DOM的 button 属性可能有如下 3个值:0 表示主鼠标按钮,1 表示中间的鼠 标按钮(鼠标滚轮按钮) ,2 表示次鼠标按钮。在常规的设置中,主鼠标按钮就是鼠标左键,而次鼠标 按钮就是鼠标右键

IE:

需要提前进行对IE还是DOM进行检测

支持 DOM 版鼠标事件的浏览器可以通过 hasFearture()方法来检测

通过检测"MouseEvents"这个特性,就可以确定 event 对象中存在的 button 属性中是否包含正 确的值

测试失败,说明是 IE,就必须对相应的值进行规范化

在使用 onmouseup 事件处理程序时,button 的值表示释放的是哪个按钮。此 外,如果不是按下或释放了主鼠标按钮,Opera 不会触发 mouseup 或 mousedown 事件

更多的事件信息

“DOM2级事件”规范在 event 对象中还提供了 detail 属性,用于给出有关事件的更多信息

detail 中包含了一个数值,表示在给定位置上发生了多少次单击

IE通过下列属性为鼠标事件提供了更多信息

鼠标滚轮事件

当用 户通过鼠标滚轮与页面交互、在垂直方向上滚动页面时(无论向上还是向下),就会触发 mousewheel 事件。这个事件可以在任何元素上面触发,终会冒泡到 document(IE8)或 window(IE9、Opera、 Chrome及 Safari)对象

特殊的 wheelDelta 属性。当用户向前滚动鼠标滚轮时,wheelDelta 是120的倍数;当用 户向后滚动鼠标滚轮时,wheelDelta 是-120的倍数

在 Opera 9.5之前的版本中,wheelDelta 值的正负号是颠倒的。如果你打算支持 早期的 Opera版本,就需要使用浏览器检测技术来确定实际的值;其他时候可以对wheelDelta的正负判断来知道的滚动方向

由于 mousewheel 事件非常流行,而且所有浏览器都支持它,所以 HTML 5也加 入了该事件

Firefox支持一个名为 DOMMouseScroll 的类似事件,也是在鼠标滚轮滚动时触发。与 mousewheel 事件一样,DOMMouseScroll 也被视为鼠标事件,因而包含与鼠标事件有关的所有属性

当向前滚动鼠标滚轮时,这个属性的值是-3 的倍数,当向后滚动 鼠标滚轮时,这个属性的值是 3 的倍数

触摸设备

在面向 iPhone和 iPod中的 Safari 开发时,要记住以下几点

无障碍性问题

键盘与文本事件

对键盘事件的支持主要遵循的是 DOM0级

在用户按了一下键盘上的字符键时,首先会触发 keydown 事件,然后紧跟着是 keypress 事件, 后会触发 keyup 事件。其中,keydown 和 keypress 都是在文本框发生变化之前被触发的;而 keyup 事件则是在文本框已经发生变化之后被触发的。如果用户按下了一个字符键不放,就会重复触发 keydown 和 keypress 事件,直到用户松开该键为止。

如果用户按下的是一个非字符键,那么首先会触发 keydown 事件,然后就是 keyup 事件。如果按 住这个非字符键不放,那么就会一直重复触发 keydown 事件,直到用户松开这个键,此时会触发 keyup 事件。

键盘事件与鼠标事件一样,都支持相同的修改键。而且,键盘事件的事件对象中 也有 shiftKey、ctrlKey、altKey 和 metaKey 属性。IE不支持 metaKey。

键码

在发生 keydown 和 keyup 事件时,event 对象的 keyCode 属性中会包含一个代码,与键盘上一 个特定的键对应

对数字字母字符键,keyCode 属性的值与 ASCII 码中对应小写字母或数字的编码相 同

注意:字母 A键的 keyCode 值为 65——与 Shift键的状态无关

所有非字符键的键码:

在Firefox和Opera中,按分号键时keyCode 值为 59,也就是 ASCII中分号的编码;但 IE和 Safari返回 186,即键盘中按键的键码

字符编码

发生 keypress 事件意味着按下的键会影响到屏幕中文本的显示

IE9、Firefox、Chrome 和 Safari的 event 对象都支持一个 charCode 属性,这个属性只有在发生 keypress 事件时才包含值,而且这个值是按下的那个键所代表字符的 ASCII 编码

keyCode 通常等于0或者也可能等于所按键的键码。IE8及之前版本和Opera则是在keyCode中保存字符的ASCII 编码。要想以跨浏览器的方式取得字符编码,必须首先检测 charCode 属性是否可用,如果不可用则使 用 keyCode

DOM3级变化

DOM3 级事件中的键盘事件,不再包含 charCode 属性,而是包含两个新属性:key 和 char

key 属性是为了取代 keyCode 而新增的,它的值是一个字符串。在按下某个字符键时,key 的值就是相应的文本字符(如“k”或“M”);在按下非字符键时, key 的值是相应键的名(如“Shift” 或“Down”)。而 char 属性在按下字符键时的行为与 key 相同,但在按下非字符键时值为 null。

IE9支持 key 属性,但不支持 char 属性。Safari 5和 Chrome支持名为 keyIdentifier 的属性, 在按下非字符键(例如 Shift)的情况下与 key 的值相同。对于字符键,keyIdentifier 返回一个格式 类似“U+0000”的字符串,表示 Unicode 值。

DOM3级事件还添加了一个名为 location 的属性,这是一个数值,表示按下了什么位置上的键: 0表示默认键盘,1表示左侧位置(例如左位的 Alt键),2表示右侧位置(例如右侧的 Shift键),3表示 数字小键盘,4表示移动设备键盘(也就是虚拟键盘),5表示手柄(如任天堂 Wii控制器)。IE9支持这 个属性。Safari和 Chrome支持名为 keyLocation 的等价属性,但即有 bug——值始终是 0,除非按下 了数字键盘(此时,值 为 3);否则,不会是 1、2、4、5

给 event 对象添加了 getModifierState()方法。这个方法接收一个参数,即等于 Shift、 Control、AltGraph 或 Meta 的字符串,表示要检测的修改键。如果指定的修改键是活动的(也就是 处于被按下的状态),这个方法返回 true,否则返回 false

IE9是唯一支持 getModifierState()方法的浏览器

textInput 事件

根据规范,当用户在可编辑区域中 输入字符时,就会触发这个事件。这个用于替代 keypress 的 textInput 事件的行为稍有不同。区别 之一就是任何可以获得焦点的元素都可以触发keypress事件,但只有可编辑区域才能触发textInput 事件。区别之二是 textInput 事件只会在用户按下能够输入实际字符的键时才会被触发,而 keypress 事件则在按下那些能够影响文本显示的键时也会触发(例如退格键)

textInput 事件主要考虑的是字符,因此它的 event 对象中还包含一个 data 属性,这个属 性的值就是用户输入的字符(而非字符编码)

event 对象上有一个属性,叫 inputMethod,表示把文本输入到文本框中的方式

设备中的键盘事件

任天堂 Wii会在用户按下 Wii遥控器上的按键时触发键盘事件

当用户按下十字键盘(键码为 175~178)、减号(170)、加号(174)、1(172)或 2(173)键时就 会触发键盘事件。但没有办法得知用户是否按下了电源开关、A、B或主页键

iOS版 Safari和 Android版 WebKit 在使用屏幕键盘时会触发键盘事件

复合事件

复合事件是针对检测和处理同时按住多个键而最终输入一个字符而设计的

确定浏览器是否支持复合事件

var isSupported = document.implementation.hasFeature("CompositionEvent", "3.0");

变动事件

DOM2级的变动(mutation)事件能在 DOM中的某一部分发生变化时给出提示

为 XML 或 HTML DOM设计的,并不特定于某种语言

检测浏览器是否支持变动事件

var isSupported = document.implementation.hasFeature("MutationEvents", "2.0");

删除节点

使用removeChild()或replaceChild()从DOM中删除节点时,首先会触发DOMNodeRemoved 事件

这个事件的目标(event.target)是被删除的节点,而 event.relatedNode 属性中包含着对 目标节点父节点的引用。在这个事件触发时,节点尚未从其父节点删除,因此其 parentNode 属性仍然 指向父节点(与 event.relatedNode 相同)。这个事件会冒泡,因而可以在 DOM的任何层次上面处 理它

如果被移除的节点包含子节点,那么在其所有子节点以及这个被移除的节点上会相继触发 DOMNodeRemovedFromDocument 事件

紧随其后触发的是 DOMSubtreeModified 事件。这个事件的目标是被移除节点的父节点;此时的 event 对象也不会提供与事件相关的其他信息

插入节点

在使用 appendChild()、replaceChild()或 insertBefore()向 DOM中插入节点时,首先会 触发 DOMNodeInserted 事件。这个事件的目标是被插入的节点,而 event.relatedNode 属性中包含 一个对父节点的引用

这个事件是冒泡的,因 此可以在 DOM的各个层次上处理它

紧接着,会在新插入的节点上面触发 DOMNodeInsertedIntoDocument 事件

这个事件不冒泡, 因此必须在插入节点之前为它添加这个事件处理程序。这个事件的目标是被插入的节点,除此之外 event 对象中不包含其他信息

后一个触发的事件是 DOMSubtreeModified,触发于新插入节点的父节点

HTML5事件

contextmenu 事件

表示何时应该显示上下文 菜单,以便开发人员取消默认的上下文菜单而提供自定义的菜单

contextmenu 事件是冒泡的,因此可以为 document 指定一个事件处理程序,用以处理页面 中发生的所有此类事件。这个事件的目标是发生用户操作的元素。在所有浏览器中都可以取消这个事件: 在兼容 DOM的浏览器中,使用 event.preventDefalut();在 IE中,将 event.returnValue 的值 设置为 false

contextmenu 事件属于鼠标事件,其事件对象中包含与光标位置有关的所有 属性

beforeunload 事件

这个事件会在浏览器卸载页面之前触发,可以通过它来取消卸载并继续使用原有页面

这个事件的意图是 将控制权交给用户。显示的消息会告知用户页面行将被卸载(正因为如此才会显示这个消息),询问用 户是否真的要关闭页面,还是希望继续留下来

IE和 Firefox、Safari和 Chrome都支持 beforeunload 事件,也都会弹出这个对话框询问用户是否 真想离开。Opera 11及之前的版本不支持 beforeunload 事件

DOMContentLoaded 事件

DOMContentLoaded 事件在形成完整的 DOM树之后就会触发, 不理会图像、JavaScript 文件、CSS 文件或其他资源是否已经下载完毕

DOMContentLoaded 支持在页面下载的早期添加事件处理程序

要处理 DOMContentLoaded 事件,可以为 document 或 window 添加相应的事件处理程序(尽管 这个事件会冒泡到 window,但它的目标实际上是 document)

IE9+、Firefox、Chrome、Safari 3.1+和 Opera 9+都支持 DOMContentLoaded 事件,通常这个事件 既可以添加事件处理程序,也可以执行其他 DOM操作。这个事件始终都会在 load 事件之前触发。

readystatechange 事件

IE为 DOM文档中的某些部分提供了 readystatechange 事件

目的是提供与文档或 元素的加载状态有关的信息,但这个事件的行为有时候也很难预料

支持 readystatechange 事件的 每个对象都有一个 readyState 属性

虽然使用 readystatechange 可以十分近似地模拟 DOMContentLoaded 事件, 但它们本质上还是不同的。在不同页面中,load 事件与 readystatechange 事件并 不能保证以相同的顺序触发。

pageshow 和 pagehide 事件

Firefox 和 Opera 有一个特性,名叫“往返缓存”(back-forward cache,或 bfcache),可以在用户使 用浏览器的“后退”和“前进”按钮时加快页面的转换速度

pageshow,这个事件在页面显示时触发,无论该页面是否来自 bfcache。在重新加 载的页面中,pageshow 会在 load 事件触发后触发;而对于 bfcache中的页面,pageshow 会在页面状 态完全恢复的那一刻触发

注意:虽然这个事件的目标是 document,但必须将其事件处理 程序添加到 window

pageshow 事件的 event 对象还包含一个名为 persisted 的布尔值属性。 如果页面被保存在了 bfcache中,则这个属性的值为 true;否则,这个属性的值为 false

pagehide 事件,该事件会在浏览器卸载页面的时候触发,而且是在 unload 事件之前触发。与 pageshow 事件一样,pagehide 在 document 上面触发,但其事件处理程 序必须要添加到 window 对象。这个事件的 event 对象也包含 persisted 属性

对于 pageshow 事件,如果页面是从 bfcache中加载的,那么 persisted 的值就是 true;对于 pagehide 事件,如果 页面在卸载之后会被保存在 bfcache中,那么 persisted 的值也会被设置为 true

指定了 onunload 事件处理程序的页面会被自动排除在 bfcache之外,即使事件 处理程序是空的

onunload 常用于撤销在 onload 中所执行的操作, 而跳过 onload 后再次显示页面很可能就会导致页面不正常

hashchange 事件

在 URL的参数列表(及 URL中“#”号后面的所有字符串) 发生变化时通知开发人员

必须要把 hashchange 事件处理程序添加给 window 对象,然后 URL参数列表只要变化就会调用 它。此时的 event 对象应该额外包含两个属性:oldURL 和 newURL。这两个属性分别保存着参数列表 变化前后的完整 URL

支持 hashchange 事件的浏览器有 IE8+、Firefox 3.6+、Safari 5+、Chrome和 Opera 10.6+。在这些 浏览器中,只有 Firefox 6+、Chrome和 Opera支持 oldURL 和 newURL 属性

检测浏览器是否支持 hashchange 事件

设备事件

orientationchange 事件

苹果公司为移动 Safari中添加了 orientationchange 事件,以便开发人员能够确定用户何时将设 备由横向查看模式切换为纵向查看模式。移动 Safari的 window.orientation 属性中可能包含 3个值: 0 表示肖像模式,90 表示向左旋转的横向模式(“主屏幕”按钮在右侧),-90 表示向右旋转的横向模 式(“主屏幕”按钮在左侧)。相关文档中还提到一个值,即 180 表示 iPhone头朝下;但这种模式至今 尚未得到支持

由于可以将 orientationchange 看成 window 事件,所以也可以通过指定 元素的 onorientationchange 特性来指定事件处理程序

MozOrientation 事件

Firefox 3.6为检测设备的方向引入了一个名为 MozOrientation 的新事件。(前缀 Moz 表示这是特 定于浏览器开发商的事件,不是标准事件。)当设备的加速计检测到设备方向改变时,就会触发这个事 件。但这个事件与 iOS中的 orientationchange 事件不同,该事件只能提供一个平面的方向变化

deviceorientation 事件

DeviceOrientation Event规范定义的 deviceorientation 事件与 MozOrientation 事件类 似。它也是在加速计检测到设备方向变化时在 window 对象上触发,而且具有与 MozOrientation 事件 相同的支持限制。不过,deviceorientation 事件的意图是告诉开发人员设备在空间中朝向哪儿,而 不是如何移动

事件对象的5个属性

devicemotion 事件

这个事件是要告诉开发人员设备 什么时候移动,而不仅仅是设备方向如何改变

事件对象包含的属性

触摸与手势事件

触摸事件

触摸 事件会在用户手指放在屏幕上面时、在屏幕上滑动时或从屏幕上移开时触发

每个触摸事件的 event 对象都提供了在鼠标事件中常见的属性: bubbles、cancelable、view、clientX、clientY、screenX、screenY、detail、altKey、shiftKey、 ctrlKey 和 metaKey。

触摸事件还包含三个用于跟踪触摸的属性

每个 Touch 对象包含的属性

支持触摸事件的浏览器包括 iOS版 Safari、Android版 WebKit、bada版 Dolfin、OS6+中的 BlackBerry WebKit、Opera Mobile 10.1+和 LG专有 OS中的 Phantom浏览器。目前只有 iOS版 Safari支持多点触摸。 桌面版 Firefox 6+和 Chrome也支持触摸事件

手势事件

三个手势事件

与触摸事件一样,每个手势事件的 event 对象都包含着标准的鼠标事件属性:bubbles、 cancelable、view、clientX、clientY、screenX、screenY、detail、altKey、shiftKey、 ctrlKey 和 metaKey。此外,还包含两个额外的属性:rotation 和 scale。其中,rotation 属性表 示手指变化引起的旋转角度,负值表示逆时针旋转,正值表示顺时针旋转(该值从 0开始)。而 scale 属性表示两个手指间距离的变化情况(例如向内收缩会缩短距离);这个值从 1 开始,并随距离拉大而 增长,随距离缩短而减小

触摸事件也会返回 rotation 和 scale 属性,但这两个属性只会在两个手指与 屏幕保持接触时才会发生变化。一般来说,使用基于两个手指的手势事件,要比管理 触摸事件中的所有交互要容易得多。

内存和性能

事件委托

事件委托利用了事件冒泡,只指定一个事 件处理程序,就可以管理某一类型的所有事件

添加一个事件处理程序,用以处理页面上发生的某种 特定类型的事件,与采取传统的做法相比具有的优点

移除事件处理程序

每当将事件处理程序指定给元素时,运行中的浏览器代码与支持页面交互的 JavaScript 代码之间就 会建立一个连接。这种连接越多,页面执行起来就越慢;内存中留有那 些过时不用的“空事件处理程序”(dangling event handler),也是造成 Web 应用程序内存与性能问题的 主要原因

造成的原因:

第一种情况就是从文档中移除带有事件处理程序的元素时。 这可能是通过纯粹的 DOM操作

注意:在事件处理程序中删除按钮也能阻止事件冒泡。目标元素在文档中是事件冒泡的前提

采用事件委托也有助于解决这个问题。如果事先知道将来有可能使用innerHTML 替换掉页面中的某一部分,那么就可以不直接把事件处理程序添加到该部分的元素 中。而通过把事件处理程序指定给较高层次的元素,同样能够处理该区域中的事件

导致“空事件处理程序”的另一种情况,就是卸载页面的时候,如果在页面被卸载之前没 有清理干净事件处理程序,那它们就会滞留在内存中。每次加载完页面再卸载页面时(可能是在两个页 面间来回切换,也可以是单击了“刷新”按钮),内存中滞留的对象数目就会增加,因为事件处理程序 占用的内存并没有被释放

模拟事件

DOM中的事件模拟

可以在 document 对象上使用 createEvent()方法创建 event 对象。这个方法接收一个参数,即 表示要创建的事件类型的字符串。在 DOM2 级中,所有这些字符串都使用英文复数形式,而在 DOM3级中都变成了单数

字符串:

模拟鼠标事件

创建新的鼠标事件对象并为其指定必要的信息,就可以模拟鼠标事件。创建鼠标事件对象的方法是 为 createEvent()传入字符串"MouseEvents"。返回的对象有一个名为 initMouseEvent()方法, 用于指定与该鼠标事件有关的信息。这个方法接收 15 个参数,分别与鼠标事件中每个典型的属性一一 对应

参数含义:

模拟键盘事件

DOM3级规定,调用 createEvent()并传入"KeyboardEvent"就可以创建一个键盘事件。返回的 事件对象会包含一个 initKeyEvent()方法,这个方法接收下列参数

在 Firefox 中,调用 createEvent()并传入"KeyEvents"就可以创建一个键盘事件。返回的事件 对象会包含一个 initKeyEvent()方法,这个方法接受下列 10个参数

模拟其他事件

模拟变动事件,可以使用 createEvent("MutationEvents")创建一个包含 initMutationEvent()方法的变动事件对象。这个方法接受的参数包括:type、bubbles、 cancelable、relatedNode、preValue、newValue、attrName 和 attrChange

浏览器中很少使用变动事件和 HTML事件,因为使用它们会受到一些限制。

自定义 DOM事件

创建新的自定义事件,可以调用 createEvent("CustomEvent")。返回的对象有 一个名为 initCustomEvent()的方法,接收如下 4个参数

IE中的事件模拟

先创建 event 对象,然后为其指 定相应的信息,然后再使用该对象来触发事件

调用 document.createEventObject()方法可以在 IE中创建 event 对象。但与 DOM方式不同 的是,这个方法不接受参数,结果会返回一个通用的 event 对象。然后,你必须手工为这个对象添加 所有必要的信息(没有方法来辅助完成这一步骤)。后一步就是在目标上调用 fireEvent()方法,这个方法接受两个参数:事件处理程序的名称和 event 对象

在调用 fireEvent()方法时,会自动为 event 对象添加 srcElement 和 type 属性;其他属性则都是必须通过手工添加的