第12章 事件 (五)

来源:互联网 发布:linux修改只读文件权限 编辑:程序博客网 时间:2024/05/20 23:07

 12.4.3 键盘事件

用户在使用键盘时会触发键盘事件。“DOM2级事件” 最初规定了键盘事件,但在最终定稿之前又删除了相应的内容。结果,对键盘事件的支持主要遵循的是 DOM0 级。“DOM3级事件” 为键盘事件制定了规范,但到 2008 年还没有哪个浏览器实现该规范。

有3个键盘事件,简述如下。

  • keydown: 当用户按下键盘上的任意键时触发,而且如果按住不放的话,会重复触发此事件。
  • keypress: 当用户按下键盘上的字符键时触发,而且如果按住不放的话,会重复触发此事件。按下 Esc 键也会触发这个事件。Safari 3.1 之前的版本也会在用户按下非字符键时触发 keypress 事件。
  • keyup: 当用户释放键盘上的键时触发。
虽然所有元素都支持以上3个事件,但只有在用户通过文本框输入文本时才最常用到。
在用户按了一下键盘上的字符键时,首先会触发 keydown 事件,然后紧跟着是 keypress 事件,最后会触发 keyup 事件。其中,keydown 和 keypress 都是在文本框发生变化之前被触发的;而 keyup事件则是在文本框已经发生变化之后被触发的。如果用户按下了一个字符键不放,就会重复触发 keydown 和 keypress 事件,直到用户松开该键为止。
如果用户按下的是一个非字符键,那么首先会触发 keydown 事件,然后就是 keyup 事件。如果按住这个非字符键不放,那么就会一直重复触发 keydown 事件,直到用户松开这个键,此时会触发 keyup 事件。
键盘事件与鼠标事件一样,都支持相同的修改键。而且,键盘事件的事件对象中也有 shiftKey、ctrlKey、altKey 和 metaKey 属性。IE 不支持 metaKey。
1.键码
在发生 keydown 和 keyup 事件时,event 对象的 keyCode 属性中会包含一个代码,与键盘上一个特定的键对应。对数字字母字符键,keyCode 属性的值与 ASCII 码中对应小写字母或数字的编码相同。因此,数字键 7 的 keyCode 值为 55,而字母 A 键的 keyCode 值为 65 ----与 Shift 键的状态无关。
DOM 和 IE 的 event 对象都支持 keyCode 属性。请看下面这个例子:
var textbox = document.getElementById("myText");
EventUtil.addHandler(textbox, "keyup", function(event){
event = EventUtil.getEvent(event);
alert(event.keyCode)
});
在这个例子中,用户每次在文本框中按键触发 keyup 事件时,都是显示 keyCode 的值。
2.字符编码
发生 keypress 事件意味着按下的键会影响到屏幕中文本的显示。在所有浏览器中,按下能够插入或删除字符的键都会触发 keypress事件;按下其他键能否触发此事件因浏览器而异。由于截止到 2008 年,尚无浏览器实现 “DOM3级事件” 规范,所以浏览器之间的键盘事件并没有多大的差异。
Firefox、Chrome 和 Safari 的 event 对象都支持一个 charCode 属性,这个属性只有在发生 keypress 事件时才包含值,而且这个值是按下的那个键所代表字符的 ASCII 编码。此时的 keyCode 通常等于 0 或者也可能等于所按键的编码。IE 和 Opera 则是在 keyCode 中保存字符的 ASCII 编码。要想以跨浏览器的方式取得字符编码,必须首先检测 charCode 属性是否可用,如果不可用则使用 keyCode,如下面的例子所示:
var EventUtil = {// 省略了其他代码getCharCode: function(event){if(typeof event.charCode == "number"){return event.charCode;} else {return event.keyCode;}},// 省略了其他代码};
这个方法首先检测 charCode 属性是否包含数值 (在不支持这个属性的浏览器中,值为 undefined),如果是,则返回该值。否则,就返回 keyCode 属性值。下面是使用这个方法的示例:
var textbox = document.getElementById("myText");
EventUtil.addHandler(textbox, "keypress", function(event){
event = EventUtil.getEvent(event);
alert(EventUtil.getCharCode(event));
});
在取得了字符编码之后,就可以使用 String.fromCharCode() 将其转换成实际的字符。

12.4.4 HTML 事件

HTML 事件指的是那些不一定与用户操作有关的事件。这些事件在 DOM 规范出现之前,都是以这种或那种形式存在的,而在 DOM 规范中保留是为了向后兼容。所谓的 HTML 事件包括下列几个事件。

  • load: 当页面完全加载后在 window 上面触发,当所有框架都加载完毕时在框架集上面触发,当图像加载完毕时在 <img> 元素上面触发,或者当嵌入的内容加载完毕时在 <object> 元素上面触发。
  • unload: 当页面完全卸载后在 window 上面触发,当所有框架都卸载后在框架集上面触发,或者当嵌入的内容卸载完毕后在 <object> 元素上面触发。
  • abort: 在用户停止下载过程时,如果嵌入的内容没有加载完,则在 <object> 元素上面触发。
  • error: 当发生 JavaScript 错误时在 window 上面触发,当无法加载图像时在 <img> 元素上面触发,当无法加载嵌入内容时在 <object> 元素上面触发,或者当有一或多个框架无法加载时在框架集上面触发。第14章将继续讨论这个事件。
  • select: 当用户选择文本框 (<input> 或 <textarea>) 中的一或多个字符时触发。第13章将继续讨论这个事件。
  • change: 当文本框 (<input> 或 <textarea>) 失去焦点或者在取得焦点后其值被改变时触发。第13章将继续讨论这个事件。
  • submit: 当用户单击提交按钮时在 <form> 元素上面触发。第13章将继续讨论这个事件。
  • reset: 当用户单击重置按钮时在 <form> 元素上面触发。第13章将继续讨论这个事件。
  • resize: 当窗口或框架的大小变化时在 window 或框架上面触发。
  • scroll: 当用户滚动带滚动条的元素中的内容时,在该元素上面触发。<body> 元素中包含所加载页面的滚动条。
  • focus: 当页面或元素获得焦点 (用户单击、按制表键进入或以其他方式激活元素)时在 window 及相应元素上面触发。
  • blur: 当页面或元素失去焦点时在 window 及相应元素上面触发。
多数 HTML 事件都与 window 对象或表单控件相关。要确定浏览器是否支持 DOM 规定的 HTML 事件,可以使用如下代码:
var isSupported = document.implementation.hasFeature("HTMLEvents", "2.0");
注意,只有根据 “DOM2级事件” 实现这些事件的浏览器才会返回 true 。而以非标准方式支持这些事件的浏览器则会返回 false。
1.加载 (load) 事件 
JavaScript 中最常用的一个事件就是 load 。当页面完全加载后 (包括所有图像、JavaScript文件、CSS文件等外部资源),就会触发 window 上面的 load 事件。有两种 onload 事件处理程序的方式。第一种方式是使用如下所示的 JavaScript 代码
EventUtil.addHandler(window, "load", function(event){
alert("Loaded!");
});
这是通过 JavaScript 来指定事件处理程序的方式,使用了本章前面定义的跨浏览器的 EventUtil 对象。与添加其他事件一样,这里也给事件处理程序传入了一个 event 对象。这个 event 对象中不包含有关这个事件的任何附加信息,但在兼容 DOM 的浏览器中, event.target 属性的值会被设置为 document,而 IE 并不会为这个事件设置 srcElement 属性。
第二种指定 onload 事件处理程序的方式是为 <body> 元素添加一个 onload 特性,如下面的例子所示:
<html>
<head>
<title>Load Event Example</title>
</head>
<body onload="alert('Loaded!')">

</body>
</html>

一般来说,在 window 上面发生的任何事件都可以在 <body/>元素中通过相应的特性来指定,因为在 HTML 中无法访问 window 元素。实际上,这只是为了保证向后兼容的一种权宜之计,但所有浏览器都能很好地支持这种方式。我们建议读者尽可能使用 JavaScript 方式。

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

图像上面也可以触发 load 事件,无论是在 DOM 中的图像元素还是 HTML 中的图像元素。因此,可以在 HTML 中为任何图像指定 onload 事件处理程序,例如:

<img src="simle.gif" onload="alert('Image loaded.')" />

这样,当例子中的图像加载完毕后就会显示一个警告框。同样的功能也可以使用 JavaScript 来实现,例如:

var image = document.getElementById("myImage");

EventUtil.addHandler(image, "load", function(event){

event = EventUtil.getEvent(event);

alert(EventUtil.getTarget(event).src);

});

这里,使用 JavaScript 指定了 onload 事件处理程序。同时也传入了 event 对象,尽管它也不包含什么有用的信息。不过,事件的目标是 <img> 元素,因此可以通过 src 属性访问并显示该信息。

在创建新的 <img> 元素时,可以为其指定一个事件处理程序,以便图像加载完毕后给出提示。此时,最重要的是要在指定 src 属性之前先指定事件,如下面的例子所示:

EventUtil.addHandler(window, "load", function(){

var image = document.createElement("img");

EventUtil.addHandler(image, "load", function(event){

event = EventUtil.getEvent(event);

alert(EventUtil.getTarget(event).src);

});

document.body.appendChild(image);

image.src = "smile.gif";

});

在这个例子中,首先为 window 指定了 onload 事件处理程序。原因在于,我们是想向 DOM 中添加一个新元素,所以必须确定页面已经加载完毕 ---- 如果在页面加载前操作 document.body 会导致错误。然后,创建一个新的图像元素,并设置了其 onload 事件处理程序。最后又将这个图像添加到页面中,还设置了它的 src 属性。这里有一点需要格外注意:新元素不一定要从添加到文档后才开始下载,只要设置了 src 属性就会开始下载。

Firefox 3 之前的版本中有一个 bug,即图像的 load 事件的目标始终是 document。Firefox 3 修复了这个 bug 。

同样的功能也可以通过使用 DOM0 级的 Image 对象实现。在 DOM 出现之前,开发人员经常使用 Image 对象在客户端预先加载图像。可以像使用 <img> 元素一样使用 Image 对象,只不过无法将其添加到 DOM 树中。下面来看一个例子:

EventUtil.addHandler(window, "load", function(){

var image = new Image();

EventUtil.addHandler(image, "load", function(){

alert("Image loaded!");

});

image.src = "smile.gif";

});

在此,我们使用 Image 构造函数创建了一个新图像的实例,然后又为它指定了事件处理程序。有的浏览器将 Image 对象实现为 <img> 元素,但并非所有浏览器都如此,所以最好将它们区别对待。

在不属于 DOM 文档的图像 (包括未添加到文档的 <img> 元素和 Image 对象) 上触发 load 事件时,IE 不会生成 event 对象。

还有一些元素也以非标准的方式支持 load 事件。在 Firefox、Opera、Chrome 和 Safari 3 及更高版本中,<script> 元素也会触发 load 事件,以便开发人员确定动态加载的 JavaScript 文件是否加载完毕。与图像不同,只有在 设置了 <script> 元素的 src 属性并将元素添加到文档后,才会开始下载 JavaScript 文件。换句话说,对于 <script> 元素而言,指定 src 属性和指定事件处理程序的先后顺序就不重要了。以下代码展示了怎样为 <script> 元素指定事件处理程序:

EventUtil.addHandler(window, "load", function(){

var script = document.createElement("script");

EventUtil.addHandler(script, "load", function(event){

alert("Loaded");

});

script.src = "exmple.js";

document.body.appendChild(script);

});

这个例子使用了跨浏览器的 EventUtil 对象为新创建的 <script> 元素指定了 onload 事件处理程序。此时,大多数浏览器中 event 对象的 target 属性引用的都是 <script> 节点,而在 Firefox3 之前的版本中,引用的则是 document 。IE 不支持 <script> 元素上的 load 事件。

IE 和 Opera 还支持 <link> 元素上的 load 事件,以便开发人员确定样式表是否加载完毕。例如:

EventUtil.addHandler(window, "load", function(){

var link = document.createElement("link");

link.type = "text/css";

link.rel = "stylesheet";

EventUtil.addHandler(link, "load", function(event){

alert("css loaded");

});

link.href = "example.css";

document.getElementsByTagName("head")[0].appendChild(link);

});

与 <script> 节点类似,在未指定 href 属性并将 <link> 元素添加到文档之前也不会开始下载样式表。

2.卸载 (unload) 事件

与 load 事件对应的是 unload 事件,这个事件在文档被完全卸载后触发。只要用户从一个页面切换到另一个页面,就会发生 unload 事件。而利用这个事件最多的情况是清除引用,以避免内存泄漏。与 load 事件类似,也有两种指定 onunload 事件处理程序的方式。第一种方式是使用 JavaScript,如下所示:

EventUtil.addHandler(window, "unload", function(event){

alert("Unloaded");

});

此时生成的 event 对象在兼容 DOM 的浏览器中只包含 target 属性 (值为 document) 。IE 则为这个事件对象提供了 srcElement 属性。

指定事件处理程序的第二种方式,也是为 <body> 元素添加一个特性 (与 load 事件相似),如下面的例子所示:

<html>

<head>

<title>Unload Event Example</title>

<body onunload="alert('Unloaded!')">


</body>

</head>

</html>

无论使用哪种方式,都要小心编写 onunload 事件处理程序中的代码。既然 unload 事件是在一切都被卸载之后才触发的,那么在页面加载后存在的那些对象,此时就不一定存在了。此时,操作 DOM 节点或者元素的样式就会导致错误。

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

3.调整大小 (resize) 事件

当浏览器窗口被调整到一个新的高度或宽度时,就会触发 resize 事件。这个事件在 window (窗口) 上面触发,因此可以通过 JavaScript 或者 <body> 元素中的 onresize 特性来指定事件处理程序。如前所述,我们还是推荐使用如下所示的 JavaScript 方式

EventUtil.addHandler(window, "resize", function(event){

alert("Resized");

});

与其他发生在 window 上的事件类似,在兼容 DOM 的浏览器中,传入事件处理程序中的 event 对象有一个 target 属性,值为 document ;而 IE 则未提供任何属性。

关于何时会触发 resize 事件,不同留啦请你有不同的机制。 IE、Safari、Chrome 和 Opera 会在浏览器窗口变化了1像素时就触发 resize 事件,然后随着变化不断重复触发。Firefox 则只会在用户停止调整窗口大小时才会触发 resize 事件。由于存在这个差别,应该注意不要在这个事件的处理程序中加入大计算量的代码,因为这些代码有可能被频繁执行,从而导致浏览器反应明显变慢。

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

4.滚动 (scroll) 事件

虽然 scroll 事件是 window 对象上发生的,但它实际表示的则是页面中相应元素的变化。在混杂模式下,可以通过 <body> 元素的 scrollLeft 和 scrollTop 来监控到这一变化;而在标准模式下,除 Safari 之外的所有浏览器都会通过 <html> 元素来反映这一变化 (Safari 仍然基于 <body> 跟踪滚动位置),如下面的例子所示:

EventUtil.addHandler(window, "scroll", function(event){

if (document.compatMode == "CSS1Compat"){

alert(document.documentElement.scrollTop);

} else {

alert(document.body.scrollTop);

}

});

以上代码指定的事件处理程序会输出页面的垂直滚动位置 -- 根据呈现模式不同使用了不同的元素。由于 Safari 3.1 之前的版本不支持 document.compatMode ,因此旧版本的浏览器就会满足第二个条件。

与 resize 事件类似,scroll 事件也会在文档被滚动期间重复被触发,所以有必要尽量保持事件处理程序的代码简单。


原创粉丝点击