第12章 事件 (四)

 

12.4 事件类型

Web浏览器中可能发生的事件有很多类型。如前所述,不同的事件类型具有不同的信息,而 "DOM2级事件" 规定了下列 5 种事件

  • UI (User Interface,用户界面) 事件,在用户与页面上的元素交互时触发;
  • 鼠标事件,当用户通过鼠标在页面上执行操作时触发;
  • 键盘事件,当用户通过键盘在页面上执行操作时触发;
  • HTML 事件,当浏览器窗口发生变化或发生特定的客户端/服务器交互时触发;
  • 变动 (mutation) 事件,当底层 DOM 结构发生变化时触发。
除了这五类事件之外,有些浏览器还会在 DOM 和 BOM 中实现其他事件。这些专有的事件一般都是根据开发人员需求定制的,没有什么规范,因此不同浏览器的实现有可能不一致。

12.4.1 UI事件

UI事件主要与元素的焦点相关,而且仅在兼容 DOM 的浏览器中受到了支持。有3个 UI 事件,分别如下:
  • DOMActive: 表示元素已经被用户操作 (通过鼠标或键盘) 激活;
  • DOMFocusIn: 表示元素已经获得了焦点;这是 HTML 中 focus 事件的普通版;
  • DOMFocusOut: 表示元素已经失去了焦点;这是 HTML 中 blur 事件的普通版。
支持这几个 UI 事件的浏览器很少,因此我们不推荐使用。本书提到它们只是为了向读者完整地展示规范。

12.4.2 鼠标事件

鼠标事件是 Web 上面最常用的一类事件,毕竟鼠标还是最主要的定位设备。DOM中定义了7个鼠标事件,简介如下。
  • 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: 表示同时按下了三个鼠标按钮
不难想见,DOM 模型下的 button 属性比 IE 模型下的 button 属性更简单也更为实用,因为同时按下多个鼠标按钮的情形十分罕见。最常见的做法就是将 IE 模型规范化为 DOM 方法,毕竟除 IE 之外的其他浏览器都原生支持 DOM 模型。而对主、中、次按钮的映射并不困难,只要将 IE 的其他选项分别转换成如同按下这三个按键中的一个即可 (同时将主按钮作为优先选取的对象)。换句话说,IE中返回的 5 和 7 会被转换成 DOM 模型中的 0。
由于单独使用能力检测无法确定差异 (两种模型有同名的 button 属性),因此必须另辟蹊径。我们知道,支持 DOM 版鼠标事件的浏览器可以通过 hasFeature() 方法来检测,所以可以再为 EventUtil 对象添加如下 getButton() 方法:
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;
				}
			}
		},
		// 省略了其他代码
	};


 

通过检测 "MouseEvents" 这个特性,就可以确定 event 对象中存在的 button 属性中是否包含正确的值。如果测试失败,说明是 IE,就必须对相应的值进行规范化。以下是使用该方法的示例:
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "mousedown", function(event){
event = EventUtil.getEvent(event);
alert(EventUtil.getButton(event));
});
在这个例子中,我们为一个 <div> 元素添加了一个 onmousedown 事件处理程序。当在这个元素上按下鼠标按钮时,会有警告框显示按钮的代码。
在使用 onmouseup 事件处理程序时,button 的值表示释放的是哪个按钮。此外,如果不是按下或释放了主鼠标按钮,Opera 不会触发 mouseup 或 mousedown 事件。
6.更多的事件信息
“DOM2级事件” 规范在 event 对象中还提供了 detail 属性,用于给出有关事件的更多信息。对于鼠标事件来说,detail中包含了一个数值,表示在给定位置上发生了多少次单击。在同一个像素上相继地发生一次 mousedown 和一次 mouseup 事件算作一次单击。detail 属性从 1 开始计数,每次单击发生后都会递增。如果鼠标在 mousedown 和 mouseup 之间移动了位置,则 detail 会被重置为 0 。
IE 也通过下列属性为鼠标事件提供了更多信息。
  • altLeft: 布尔值,表示是否按下了 Alt 键。如果 altLeft 的值为 true,则 altKey 的值也为 true。
  • ctrlLeft: 布尔值,表示是否按下了 Ctrl 键。如果 ctrlLeft 的值为 true,则 ctrlKey 的值也为 true。
  • offsetX: 光标相对于目标元素边界的 x 坐标。
  • offsetY: 光标相对于目标元素边界的 y 坐标。
  • shiftLeft: 布尔值,表示是否按下了 Shift 键。如果 shiftLeft 的值为 true,则 shiftKey 的值也为 true。
这些属性的用处并不大,原因一方面只有 IE 支持它们,另一方面是它们提供的信息要么没有什么价值,要么可以通过其他方式计算的来。



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值