13.4 事件类型 (UI、焦点事件)
一、事件的类型
- 如前所述,不同的事件类型具有不同的信息,而**“DOM3 级事件”规定了**以下几类事件。
- 除了这几类事件之外,HTML5 也定义了一组事件,而有些浏览器还会在 DOM 和 BOM 中实现其他专有事件。这些专有的事件一般都是根据开发人员需求定制的,没有什么规范,因此不同浏览器的实现有可能不一致。
- DOM3 级事件模块在 DOM2 级事件模块基础上重新定义了这些事件,也添加了一些新事件。包括 IE9 在内的所有主流浏览器都支持 DOM2 级事件。IE9 也支持 DOM3 级事件。
二、UI事件
UI 事件指的是那些不一定与用户操作有关的事件。
1、现有的UI事件
-
多数这些事件都与 window 对象或表单控件相关。
除了 DOMActivate 之外,其他事件在 DOM2 级事件中都归为 HTML 事件(DOMActivate 在 DOM2级中仍然属于 UI 事件)。 -
要确定浏览器是否支持 DOM2 级事件规定的 HTML 事件,可以使用如下代码:
var isSupported = document.implementation.hasFeature("HTMLEvents", "2.0");
注意,只有根据“DOM2 级事件”实现这些事件的浏览器才会返回 true。而以非标准方式支持这些事件的浏览器则会返回 false。
-
要确定浏览器是否支持“DOM3 级事件”定义的事件,可以使用如下代码:
var isSupported = document.implementation.hasFeature("UIEvent", "3.0");
2、load事件
- 当页面完全加载后(包括所有图像、JavaScript 文件、 CSS 文件等外部资源),就会触发 window 上面的 load 事件。
- 有两种定义 onload 事件处理程序的方式。
- 第一种方式是使用如下所示的 JavaScript 代码:
与添加其他事件一样,这里也给事件处理程序传入了一个 event 对象。这个 event 对象中不包含有关这个事件的任何附加信息,但在兼容 DOM 的浏览器中,event.target 属性的值会被设置为 document,而 IE 并不会为这个事件设置 srcElement 属性。【不理解,为什么不包含?自测打印是包含的。】 - 第二种指定 onload 事件处理程序的方式是为
<body>
元素添加一个 onload 特性,如下面的例子 所示:
<!DOCTYPE html>
<html>
<head>
<title>Load Event Example</title>
</head>
<body onload="alert('Loaded!')">
</body>
</html>
一般来说,在 window 上面发生的任何事件都可以在<body>
元素中通过相应的特性来指定,因为在 HTML 中无法访问 window 元素【元素无法获取只能取得window对象】。实际上,这只是为了保证向后兼容的一种权宜之计,但所有浏览器 都能很好地支持这种方式。我们建议读者尽可能使用 JavaScript 方式。
- 图像上面也可以触发 load 事件,无论是在 DOM 中的图像元素还是 HTML 中的图像元素。因此, 可以在 HTML 中为任何图像指定 onload 事件处理程序,例如:
<img src="smile.gif" onload="alert('Image loaded.')">
这样,当例子中的图像加载完毕后就会显示一个警告框。
-
同样的功能也可以使用 JavaScript 来实现, 例如:
这里,使用 JavaScript 指定了 onload 事件处理程序。同时也传入了 event 对象,尽管它也不包含什么有用的信息【又一次提到?难道是因为load事件就这样图书吗?】。不过,事件的目标是<img>
元素,因此可以通过 src 属性访问并显示该信息。 -
在创建新的
<img>
元素时,可以为其指定一个事件处理程序,以便图像加载完毕后给出提示。此时, 最重要的是要在指定 src 属性之前先指定事件,如下面的例子所示。
在这个例子中,首先为 window 指定了 onload 事件处理程序。原因在于,我们是想向 DOM 中添 加一个新元素,所以必须确定页面已经加载完毕——如果在页面加载前操作 document.body 会导致错误。然后,创建了一个新的图像元素,并设置了其 onload 事件处理程序。最后又将这个图像添加到页面中,还设置了它的 src 属性。
这里有一点需要格外注意:新图像元素不一定要从添加到文档后才开始下载,只要设置了 src 属性就会开始下载。
- 同样的功能也可以通过使用 DOM0 级的 Image 对象实现。在 DOM出现之前,开发人员经常使用 Image 对象在客户端预先加载图像。可以像使用
<img>
元素一样使用 Image 对象,只不过无法将其添加到 DOM 树中。下面来看一个例子。
在此,我们使用 Image 构造函数创建了一个新图像的实例,然后又为它指定了事件处理程序。有的浏览器将 Image 对象实现为<img>
元素,但并非所有浏览器都如此,所以最好将它们区别对待。
不属于DOM文档的图像(包括未添加到文档的
<img>
元素和Image对象)上触发load事件时,IE8及之前版本不会生成event对象,IE9修复了这个问题。
- 还有一些元素也以非标准的方式支持 load 事件。在 IE9+、Firefox、Opera、Chrome 和 Safari 3+及 更高版本中,
<script>
元素也会触发 load 事件,以便开发人员确定动态加载的 JavaScript 文件是否加载完毕。
- 与图像不同,只有在设置了
<script>
元素的 src 属性并将该元素添加到文档后,才会开始下 载 JavaScript 文件。换句话说,对于<script>
元素而言,指定 src 属性和指定事件处理程序的先后顺序就不重要了【图像是只要设置了src属性就会开始下载,如果在指定src之后再指定事件处理顺序,那时图像可能已经加载完,事件监听不到,无法触发事件】。以下代码展示了怎样为<script>
元素指定事件处理程序。
这个例子使用了跨浏览器的 EventUtil 对象为新创建的<script>
元素指定了 onload 事件处理程序。此时,大多数浏览器中 event 对象的 target 属性引用的都是<script>
节点,而在 Firefox 3 之前 的版本中,引用的则是 document。IE8 及更早版本不支持<script>
元素上的 load 事件。
- IE 和 Opera 还支持
<link>
元素上的 load 事件,以便开发人员确定样式表是否加载完毕。例如:
与<script>
节点类似,在未指定 href 属性并将<link>
元素添加到文档之前也不会开始下载样式表。
3、unload事件
- 与 load 事件对应的是 unload 事件,这个事件在文档被完全卸载后触发。只要用户从一个页面切换到另一个页面,就会发生 unload 事件。而利用这个事件最多的情况是清除引用,以避免内存泄漏。
- 与 load 事件类似,也有两种指定 onunload 事件处理程序的方式。
- 第一种方式是使用 JavaScript,如下所示:
此时生成的 event 对象在兼容 DOM 的浏览器中只包含 target 属性(值为document)。IE8 及之前版本则为这个事件对象提供了 srcElement 属性。【只有unload中的事件对象提供了srcELement属性吗?】 - 指定事件处理程序的第二种方式,也是为
<body>
元素添加一个特性(与 load 事件相似),如下面的例子所示:
无论使用哪种方式,都要小心编写onunload事件处理程序中的代码。既然unload事件是在一切都被卸载之后才触发,那么在页面加载后存在的那些对象,此时就不一定存在了。此时,操作 DOM 节点或者元素的样式就会导致错误。
根据“DOM2 级事件”,应该在
<body>
元素而非 window 对象上面触发 unload 事件。不过,所有浏览器都在 window 上实现了 unload 事件,以确保向后兼容。
4、resize 事件
- 当浏览器窗口被调整到一个新的高度或宽度时,就会触发 resize 事件。这个事件在 window(窗口)上面触发,因此可以通过 JavaScript 或者
<body>
元素中的 onresize 特性来指定事件处理程序。如前所述,我们还是推荐使用如下所示的 JavaScript 方式:
EventUtil.addHandler(window, "resize", function(event){
alert("Resized");
});
与其他发生在 window 上的事件类似,在兼容 DOM 的浏览器中,传入事件处理程序中的 event 对 象有一个 target 属性,值为 document;而 IE8 及之前版本则未提供任何属性。
-
关于何时会触发 resize 事件,不同浏览器有不同的机制。
IE、Safari、Chrome 和 Opera 会在浏览器窗口变化了 1 像素时就触发 resize 事件,然后随着变化不断重复触发。Firefox 则只会在用户停止调 整窗口大小时才会触发 resize 事件。
由于存在这个差别,应该注意不要在这个事件的处理程序中加入大计算量的代码,因为这些代码有可能被频繁执行,从而导致浏览器反应明显变慢。
浏览器窗口最小化或最大化时也会触发 resize 事件。
5、scroll事件
虽然 scroll 事件是在 window 对象上发生的,但它实际表示的则是页面中相应元素的变化。在混杂模式下,可以通过<body>
元素的 scrollLeft 和 scrollTop 来监控到这一变化;而在标准模式下, 除 Safari 之外的所有浏览器都会通过<html>
元素来反映这一变化(Safari 仍然基于<body>
跟踪滚动位 置),如下面的例子所示
以上代码指定的事件处理程序会输出页面的垂直滚动位置——根据呈现模式不同使用了不同的元 素。由于 Safari 3.1 之前的版本不支持 document.compatMode,因此旧版本的浏览器就会满足第二个条件。
与 resize 事件类似,scroll 事件也会在文档被滚动期间重复被触发,所以有必要尽量保持事件 处理程序的代码简单。
三、焦点事件
- 焦点事件会在页面元素获得或失去焦点时触发。利用这些事件并与
document.hasFocus()
方法及document.activeElement
属性配合,可以知晓用户在页面上的行踪。有以下 6 个焦点事件。
- 这一类事件中
最主要的两个是 focus 和 blur
,它们都是 JavaScript 早期就得到所有浏览器支持的事件。这些事件的最大问题是它们不冒泡。因此,IE 的 focusin 和 focusout 与 Opera 的 DOMFocusIn 和 DOMFocusOut 才会发生重叠。IE 的方式最后被 DOM3 级事件采纳为标准方式。
- 当焦点从页面中的一个元素移动到另一个元素加粗样式,会依次触发下列事件:
(1)focusout
在失去焦点的元素上触发;
(2)focusin
在获得焦点的元素上触发;
(3)blur
在失去焦点的元素上触发;
(4)DOMFocusOut
在失去焦点的元素上触发;
(5)focus
在获得焦点的元素上触发;
(6)DOMFocusIn
在获得焦点的元素上触发。
其中,blur、DOMFocusOut和focusout的事件目标是失去焦点的元素;而focus、DOMFocusIn和 focusin 的事件目标是获得焦点的元素。 - 要确定浏览器是否支持这些事件,可以使用如下代码:
var isSupported = document.implementation.hasFeature("FocusEvent", "3.0");
- 即使 focus 和 blur 不冒泡,也可以在捕获阶段侦听到它们。