12.4 事件类型
Web浏览器中可能发生的事件有很多类型。如前所述,不同的事件类型具有不同的信息,而 "DOM2级事件" 规定了下列 5 种事件:
- UI (User Interface,用户界面) 事件,在用户与页面上的元素交互时触发;
- 鼠标事件,当用户通过鼠标在页面上执行操作时触发;
- 键盘事件,当用户通过键盘在页面上执行操作时触发;
- HTML 事件,当浏览器窗口发生变化或发生特定的客户端/服务器交互时触发;
- 变动 (mutation) 事件,当底层 DOM 结构发生变化时触发。
12.4.1 UI事件
- DOMActive: 表示元素已经被用户操作 (通过鼠标或键盘) 激活;
- DOMFocusIn: 表示元素已经获得了焦点;这是 HTML 中 focus 事件的普通版;
- DOMFocusOut: 表示元素已经失去了焦点;这是 HTML 中 blur 事件的普通版。
12.4.2 鼠标事件
- click: 在用户单击主鼠标按钮 (一般是左边的按钮) 或者按下回车键时触发。这一点对确保易访问性很重要,意味着 onclick 事件处理程序既可以通过键盘也可以通过鼠标执行。
- dblclick: 在用户双击主鼠标按钮 (一般是左边的按钮) 时触发。从技术上说,这个事件并不是 DOM 事件规范中规定的。
- mousedown: 在用户按下了任意鼠标按钮时触发。不能通过键盘触发这个事件。
- mouseout: 在鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发。又移入的另一个元素可能位于前一个元素的外部,也可能是这个元素的子元素。不能通过键盘触发这个事件。
- mouseover: 在鼠标指针位于一个元素外部,然后用户将其首次移入另一个元素边界之内时触发。不能通过键盘触发这个事件。
- mouseup: 在用户释放鼠标按钮时触发。不能通过键盘触发这个事件。
- mousemove: 当鼠标指针在元素内部移动时重复地触发。不能通过键盘触发这个事件。
只有在同一个元素上相继触发 mousedown 和 mouseup 事件,才会触发 click 事件;如果 mousedown 或 mouseup 中的一个被取消,就不会触发 click 事件。类似地,只有触发两次 click 事件,才会触发一次 dblclick 事件。如果有代码阻止了连续两次触发 click 事件 (可能是直接取消 click 事件,也可能通过取消 mousedown 或 mouseup 间接实现),那么就不会触发 dblclick 事件了。这4个事件触发的顺序始终如下:
(1) mousedown
(2) mouseup
(3) click
(4) mousedown
(5) mouseup
(6) click
(7) dblclick
显然,click 和 dblclick 事件都会依赖于其他先行事件的触发;而 mousedown 和 mouseup 则不受其他事件的影响。
1.客户区坐标位置
鼠标事件都是在浏览器视口中的特定的位置上发生的。这个位置信息保存在事件对象的 clientX 和 clientY 属性中。所有浏览器都支持这两个属性,它们的值表示事件发生时鼠标指针在视口中的水平和垂直坐标。图 12-4 展示了视口中客户端坐标位置的含义。
可以使用类似下列代码取得鼠标事件的客户端坐标信息:
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event){
event = EventUtil.getEvent(event);
alert("Client coordinates: " + event.clientX + "," + event.clientY);
});
这里为一个 <div/> 元素指定了 onclick 事件处理程序。当用户单击这个元素时,就会看到事件的客户端坐标信息。注意,这些值中不包含页面滚动的距离,因此这个位置并不表示鼠标在页面上的位置。
2.屏幕坐标位置
鼠标事件发生时,不仅会有相对于浏览器窗口的位置,还有一个相对于整个电脑屏幕的位置。而通过 screenX 和 screenY 属性就可以确定鼠标事件发生时鼠标指针相对于整个屏幕的坐标信息。图 12-5 展示了浏览器中屏幕坐标的含义。
可以使用类似下面的代码取得鼠标事件的屏幕坐标:
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(){
event = EventUtil.getEvent(event);
alert("Screen coordinates: " + event.screenX + "," + event.screenY);
});
与前一个例子类似,这里也是为 <div/> 元素指定了一个 onclick 事件处理程序。当这个元素被单击时,就会显示出事件的屏幕坐标信息了。
3.修改键
虽然鼠标事件主要是使用鼠标来触发的,但在按下鼠标时键盘上的某些键的状态也可以影响到所要采取的操作。这些修改键就是 Shift、Ctrl、Alt 和 Meta (在 Windows 键盘中是 Windows 键,在苹果机中是 Cmd 键),它们经常被用来修改鼠标事件和行为。DOM 为此规定了4个属性,表示这些修改键的状态:shiftKey、ctrlKey、altKey 和 metaKey 。这些属性中包含的都是布尔值,如果相应的键被按下了,则值为 true,否则值为 false。当某个鼠标事件发生时,通过检测这几个属性就可以确定用户是否同时按下了其中的键。来看下面的例子:
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event){
event = EventUtil.getEvent(event);
var keys = new Array();
if (event.shiftKey) {
keys.push("shift");
}
if (event.ctrlKey) {
keys.push("ctrl");
}
if (event.altKey) {
keys.push("alt");
}
if (event.metaKey){
keys.push("meta");
}
alert("Keyss: " + keys.join(","));
});
在这个例子中,我们通过一个 onclick 事件处理程序检测了不同修改键的状态。数组 keys 中包含着被按下的修改键的名称。换句话说,如果有属性值为 true ,就会将对应修改键的名称添加到 keys 数组中。在事件处理程序的最后,有一个警告框将检测到的键的信息显示给用户。
Firefox、Safari、Chrome 和 Opera 都支持这4个键。IE不支持 metaKey 属性。
4.相关元素
在发生 mouseover 和 mouseout 事件时,还会涉及更多的元素。这两个事件都会涉及把鼠标指针从一个元素的边界之内移动到另一个元素的边界之内。对 mouseover 事件而言,事件的主目标是获得光标的元素,而相关元素就是那个失去光标的元素。类似地,对 mouseout 事件而言,事件的主目标是失去光标的元素,而相关元素则是获得光标的元素。来看下面的例子:
<html>
<head>
<title>Related Elments Example</title>
</head>
<body>
<div id="myDiv" style="background-color:red;height:100px;width:100px">Move the mouse from here to the white</div>
</body>
</html>
这个例子会在页面上显示一个 <div> 元素。如果鼠标指针一开始位于这个 <div> 元素上,然后移出了这个元素,那么就会在 <div> 元素上触发 mouseout 事件,相关元素就是 <body> 元素。与此同时,<body> 元素上面会触发 mouseover 事件,而相关元素变成了 <div>。
DOM 通过 event 对象的 relatedTarget 属性提供了相关元素的信息。这个属性只对于 mouseover 和 mouseout 事件才包含值;对于其他事件,这个属性的值是 null。IE不支持 relatedTarget 属性,但提供了保存着同样信息的不同属性。在 mouseover 事件触发时,IE 的 fromElement 属性中保存了相关元素;在 mouseout 事件触发时,IE 的 toElement 属性中保存着相关元素。可以把下面这个跨浏览器取得相关元素的方法添加到 EventUtil 对象中:
var EventUtil = {
// 省略了其他代码
getRelatedTarget: function(event){
if(event.relatedTarget){
return event.relatedTarget;
} else if(event.toElement){
return event.toElement;
} else if(event.fromElement){
return event.fromElement;
} else {
return null;
}
},
// 省略了其他代码
};
与以前添加的跨浏览器方法一样,这个方法也使用了特性检测来确定返回哪个值。可以像下面这样使用 EventUtil.getRelatedTarget() 方法:
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "mouseout", function(event){
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
var relatedTarget = EventUtil.getRelatedTarget(event);
alert("Moused out of" + target.tagName + " to" + relatedTarget.tagName);
});
这个例子为 <div> 元素的 mouset 事件注册了一个事件处理程序。当事件触发时,会有一个警告框显示鼠标移出和移入的元素信息。
5.鼠标按钮
只有在主鼠标按钮被单击时才会触发 click 事件,因此检测按钮的信息并不是必要的。但对于 mousedown 和 mouseup 事件来说,则在其 event 对象存在一个 button 属性,表示按下或释放的按钮。DOM 的 button 属性可能有如下 3 个值 :0 表示主鼠标按钮,1 表示中间的鼠标按钮 (鼠标滚轮按钮),2 表示次鼠标按钮。在常规的设置中,主鼠标按钮就是鼠标左键,而次鼠标按钮就是鼠标右键。
IE 也提供了 button 属性,但这个属性的值与 DOM 的 button 属性有很大差异。
- 0: 表示没有按下按钮
- 1: 表示按下了主鼠标按钮
- 2: 表示按下了次鼠标按钮
- 3: 表示同时按下了主、次鼠标按钮
- 4: 表示按下了中间的鼠标按钮
- 5: 表示同时按下了主鼠标按钮和中间的鼠标按钮
- 6: 表示同时按下了次鼠标按钮和中间的鼠标按钮
- 7: 表示同时按下了三个鼠标按钮
var EventUtil = {
// 省略了其他代码
getButton: function(event){
if(document.implementation.hasFeature("MouseEvents", "2.0")){
return event.button;
} else {
switch(event.button) {
case 0:
case 1:
case 3:
case 5:
case 7:
return 0;
case 2:
return 2;
case 4:
return 1;
}
}
},
// 省略了其他代码
};
- altLeft: 布尔值,表示是否按下了 Alt 键。如果 altLeft 的值为 true,则 altKey 的值也为 true。
- ctrlLeft: 布尔值,表示是否按下了 Ctrl 键。如果 ctrlLeft 的值为 true,则 ctrlKey 的值也为 true。
- offsetX: 光标相对于目标元素边界的 x 坐标。
- offsetY: 光标相对于目标元素边界的 y 坐标。
- shiftLeft: 布尔值,表示是否按下了 Shift 键。如果 shiftLeft 的值为 true,则 shiftKey 的值也为 true。