鼠标事件是Web 开发中最经常使用的一类事件,毕竟鼠标仍是最主要的定位设备。DOM3 级事件中定义了9 个鼠标事件,简介以下。
click:在用户单击主鼠标按钮(通常是左边的按钮)或者按下回车键时触发。这一点对确保易访问性很重要,意味着onclick 事件处理程序既能够经过键盘也能够经过鼠标执行。html
页面上的全部元素都支持鼠标事件。除了mouseenter 和mouseleave,全部鼠标事件都会冒泡,也能够被取消,而取消鼠标事件将会影响浏览器的默认行为。取消鼠标事件的默认行为还会影响其余事件,由于鼠标事件与其余事件是密不可分的关系。
只有在同一个元素上相继触发mousedown 和mouseup 事件,才会触发click 事件;若是mousedown 或mouseup 中的一个被取消,就不会触发click 事件。相似地,只有触发两次click 事件,才会触发一次dblclick 事件。若是有代码阻止了连续两次触发click 事件(多是直接取消click事件,也可能经过取消mousedown 或mouseup 间接实现),那么就不会触发dblclick 事件了。这4个事件触发的顺序始终以下:web
显然,click 和dblclick 事件都会依赖于其余先行事件的触发;而mousedown 和mouseup 则不受其余事件的影响。
IE8 及以前版本中的实现有一个小bug,所以在双击事件中,会跳过第二个mousedown 和click事件,其顺序以下:api
IE9 修复了这个bug,以后顺序就正确了。使用如下代码能够检测浏览器是否支持以上DOM2 级事件(除dbclick、mouseenter 和mouseleave 以外):数组
var isSupported = document.implementation.hasFeature("MouseEvents", "2.0");
要检测浏览器是否支持上面的全部事件,可使用如下代码:浏览器
var isSupported = document.implementation.hasFeature("MouseEvent", "3.0")
注意,DOM3 级事件的feature 名是"MouseEvent",而非"MouseEvents"。
鼠标事件中还有一类滚轮事件。而说是一类事件,其实就是一个mousewheel 事件。这个事件跟踪鼠标滚轮,相似于Mac 的触控板。函数
鼠标事件都是在浏览器视口中的特定位置上发生的。这个位置信息保存在事件对象的clientX 和clientY 属性中。全部浏览器都支持这两个属性,它们的值表示事件发生时鼠标指针在视口中的水平和垂直坐标。图13-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 事件处理程序。当用户单击这个元素时,就会看到事件的客户端坐标信息。注意,这些值中不包括页面滚动的距离,所以这个位置并不表示鼠标在页面上的位置。网站
经过客户区坐标可以知道鼠标是在视口中什么位置发生的,而页面坐标经过事件对象的pageX 和pageY 属性,能告诉你事件是在页面中的什么位置发生的。换句话说,这两个属性表示鼠标光标在页面中的位置,所以坐标是从页面自己而非视口的左边和顶边计算的。
如下代码能够取得鼠标事件在页面中的坐标:指针
var div = document.getElementById("myDiv"); EventUtil.addHandler(div, "click", function(event) { event = EventUtil.getEvent(event); alert("Page coordinates: " + event.pageX + "," + event.pageY); });
运行一下
在页面没有滚动的状况下,pageX 和pageY 的值与clientX 和clientY 的值相等。
IE8 及更早版本不支持事件对象上的页面坐标,不过使用客户区坐标和滚动信息能够计算出来。这时候须要用到document.body(混杂模式)或document.documentElement(标准模式)中的scrollLeft 和scrollTop 属性。计算过程以下所示:htm
var div = document.getElementById("myDiv"); EventUtil.addHandler(div, "click", function(event) { event = EventUtil.getEvent(event); var pageX = event.pageX, pageY = event.pageY; if (pageX === undefined) { pageX = event.clientX + (document.body.scrollLeft || document.documentElement.scrollLeft); } if (pageY === undefined) { pageY = event.clientY + (document.body.scrollTop || document.documentElement.scrollTop); } alert("Page coordinates: " + pageX + "," + pageY); });
鼠标事件发生时,不只会有相对于浏览器窗口的位置,还有一个相对于整个电脑屏幕的位置。而经过screenX 和screenY 属性就能够肯定鼠标事件发生时鼠标指针相对于整个屏幕的坐标信息。图13-5展现了浏览器中屏幕坐标的含义。
可使用相似下面的代码取得鼠标事件的屏幕坐标:
var div = document.getElementById("myDiv"); EventUtil.addHandler(div, "click", function(event) { event = EventUtil.getEvent(event); alert("Screen coordinates: " + event.screenX + "," + event.screenY); });
运行一下
与前一个例子相似,这里也是为<div>元素指定了一个onclick 事件处理程序。当这个元素被单击时,就会显示出事件的屏幕坐标信息了。
虽然鼠标事件主要是使用鼠标来触发的,但在按下鼠标时键盘上的某些键的状态也能够影响到所要采起的操做。这些修改键就是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("Keys: " + keys.join(",")); });
运行一下
在这个例子中,咱们经过一个onclick 事件处理程序检测了不一样修改键的状态。数组keys 中包含着被按下的修改键的名称。换句话说,若是有属性值为true,就会将对应修改键的名称添加到keys数组中。在事件处理程序的最后,有一个警告框将检测到的键的信息显示给用户。
IE九、Firefox、Safari、Chrome 和Opera 都支持这4 个键。IE8 及以前版本不支持metaKey 属性。
在发生mouseover 和mouserout 事件时,还会涉及更多的元素。这两个事件都会涉及把鼠标指针从一个元素的边界以内移动到另外一个元素的边界以内。对mouseover 事件而言,事件的主目标是得到光标的元素,而相关元素就是那个失去光标的元素。相似地,对mouseout 事件而言,事件的主目标是失去光标的元素,而相关元素则是得到光标的元素。来看下面的例子。
<!DOCTYPE html> <html> <head> <title>Related Elements Example</title> </head> <body> <div id="myDiv" style="background-color:red;height:100px;width:100px;"></div> </body> </html>
运行一下
这个例子会在页面上显示一个<div>元素。若是鼠标指针一开始位于这个<div>元素上,而后移出了这个元素,那么就会在<div>元素上触发mouseout 事件,相关元素就是<body>元素。与此同时,<body>元素上面会触发mouseover 事件,而相关元素变成了<div>。
DOM经过event 对象的relatedTarget 属性提供了相关元素的信息。这个属性只对于mouseover和mouseout 事件才包含值;对于其余事件,这个属性的值是null。IE8及以前版本不支持relatedTarget属性,但提供了保存着一样信息的不一样属性。在mouseover 事件触发时,IE 的fromElement 属性中保存了相关元素;在mouseout 事件触发时,IE 的toElement 属性中保存着相关元素。(IE9 支持全部这些属性。)能够把下面这个跨浏览器取得相关元素的方法添加到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.js
与之前添加的跨浏览器方法同样,这个方法也使用了特性检测来肯定返回哪一个值。能够像下面这样使用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>元素的mouseout 事件注册了一个事件处理程序。当事件触发时,会有一个警告框显示鼠标移出和移入的元素信息。
只有在主鼠标按钮被单击(或键盘回车键被按下)时才会触发click 事件,所以检测按钮的信息并非必要的。但对于mousedown 和mouseup 事件来讲,则在其event 对象存在一个button 属性,表示按下或释放的按钮。DOM的button 属性可能有以下3 个值:0 表示主鼠标按钮,1 表示中间的鼠标按钮(鼠标滚轮按钮),2 表示次鼠标按钮。在常规的设置中,主鼠标按钮就是鼠标左键,而次鼠标按钮就是鼠标右键。
IE8 及以前版本也提供了button 属性,但这个属性的值与DOM 的button 属性有很大差别。
不难想见,DOM 模型下的button 属性比IE 模型下的button 属性更简单也更为实用,由于同时按下多个鼠标按钮的情形十分罕见。最多见的作法就是将IE 模型规范化为DOM 方式,毕竟除IE8 及更早版本以外的其余浏览器都原生支持DOM 模型。而对主、中、次按钮的映射并不困难,只要将IE 的其余选项分别转换成如同按下这三个按键中的一个便可(同时将主按钮做为优先选取的对象)。换句话说,IE 中返回的5 和7 会被转换成DOM 模型中的0。
因为单独使用能力检测没法肯定差别(两种模型有同名的button 属性),所以必须另辟蹊径。咱们知道,支持DOM 版鼠标事件的浏览器能够经过hasFearture()方法来检测,因此能够再为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: case 6: return 2; case 4: return 1; } } }, //省略了其余代码 };
EventUtil.js
经过检测"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事件。
“DOM2 级事件”规范在event 对象中还提供了detail 属性,用于给出有关事件的更多信息。对于鼠标事件来讲,detail 中包含了一个数值,表示在给定位置上发生了多少次单击。在同一个元素上相继地发生一次mousedown 和一次mouseup 事件算做一次单击。detail 属性从1 开始计数,每次单击发生后都会递增。若是鼠标在mousedown 和mouseup 之间移动了位置,则detail 会被重置为0。
IE 也经过下列属性为鼠标事件提供了更多信息。
这些属性的用处并不大,缘由一方面是只有IE 支持它们,另外一方是它们提供的信息要么没有什么价值,要么能够经过其余方式计算得来。
IE 6.0 首先实现了mousewheel 事件。此后,Opera、Chrome 和Safari 也都实现了这个事件。当用户经过鼠标滚轮与页面交互、在垂直方向上滚动页面时(不管向上仍是向下),就会触发mousewheel事件。这个事件能够在任何元素上面触发,最终会冒泡到document(IE8)或window(IE九、Opera、Chrome 及Safari)对象。与mousewheel 事件对应的event 对象除包含鼠标事件的全部标准信息外,还包含一个特殊的wheelDelta 属性。当用户向前滚动鼠标滚轮时,wheelDelta 是120 的倍数;当用户向后滚动鼠标滚轮时,wheelDelta 是120 的倍数。图13-6 展现了这个属性。
将mousewheel 事件处理程序指定给页面中的任何元素或document 对象,便可处理鼠标滚轮的交互操做。来看下面的例子。
EventUtil.addHandler(document, "mousewheel", function(event){ event = EventUtil.getEvent(event); alert(event.wheelDelta); });
这个例子会在发生mousewheel 事件时显示wheelDelta 的值。多数状况下,只要知道鼠标滚轮滚动的方向就够了,而这经过检测wheelDelta 的正负号就能够肯定。
有一点要注意:在Opera 9.5 以前的版本中,wheelDelta 值的正负号是颠倒的。若是你打算支持早期的Opera 版本,就须要使用浏览器检测技术来肯定实际的值,以下面的例子所示。
EventUtil.addHandler(document, "mousewheel", function(event) { event = EventUtil.getEvent(event); var delta = (client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta: event.wheelDelta); alert(delta); });
运行一下
以上代码使用第9 章建立的client 对象检测了浏览器是否是早期版本的Opera。
因为mousewheel 事件很是流行,并且全部浏览器都支持它,因此HTML 5 也加入了该事件。
Firefox 支持一个名为DOMMouseScroll 的相似事件,也是在鼠标滚轮滚动时触发。与mousewheel事件同样,DOMMouseScroll 也被视为鼠标事件,于是包含与鼠标事件有关的全部属性。而有关鼠标滚轮的信息则保存在detail 属性中,当向前滚动鼠标滚轮时,这个属性的值是-3 的倍数,当向后滚动鼠标滚轮时,这个属性的值是3 的倍数。图13-7 展现了这个属性。
能够将DOMMouseScroll 事件添加到页面中的任何元素,并且该事件会冒泡到window 对象。所以,能够像下面这样针对这个事件来添加事件处理程序。
EventUtil.addHandler(window, "DOMMouseScroll", function(event) { event = EventUtil.getEvent(event); alert(event.detail); });
运行一下
这个简单的事件处理程序会在鼠标滚轮滚动时显示detail 属性的值。
若要给出跨浏览器环境下的解决方案,第一步就是建立一个可以取得鼠标滚轮增量值(delta)的方法。下面是咱们添加到EventUtil 对象中的这个方法。
var EventUtil = { //省略了其余代码 getWheelDelta: function(event) { if (event.wheelDelta) { return (client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta: event.wheelDelta); } else { return - event.detail * 40; } }, //省略了其余代码 };
EventUtil.js
这里,getWheelDelta()方法首先检测了事件对象是否包含wheelDelta 属性,若是是则经过浏览器检测代码肯定正确的值。若是wheelDelta 不存在,则假设相应的值保存在detail 属性中。因为Firefox 的值有所不一样,所以首先要将这个值的符号反向,而后再乘以40,就能够保证与其余浏览器的值相同了。有了这个方法以后,就能够将相同的事件处理程序指定给mousewheel 和DOMMouse-Scroll 事件了,例如:
(function() { function handleMouseWheel(event) { event = EventUtil.getEvent(event); var delta = EventUtil.getWheelDelta(event); alert(delta); } EventUtil.addHandler(document, "mousewheel", handleMouseWheel); EventUtil.addHandler(document, "DOMMouseScroll", handleMouseWheel); })();
运行一下
咱们将相关代码放在了一个私有做用域中,从而不会让新定义的函数干扰全局做用域。这里定义的handleMouseWheel()函数能够用做两个事件的处理程序(若是指定的事件不存在,则为该事件指定处理程序的代码就会静默地失败)。因为使用了EventUtil.getWheelDelta()方法,咱们定义的这个事件处理程序函数能够适用于任何一种状况。
iOS 和Android 设备的实现很是特别,由于这些设备没有鼠标。在面向iPhone 和iPod 中的Safari开发时,要记住如下几点。
若是屏幕没有所以变化,那么会依次发生mousedown、mouseup 和click 事件。轻击不可单击的元素不会触发任何事件。可单击的元素是指那些单击可产生默认操做的元素(如连接),或者那些已经被指定了onclick 事件处理程序的元素。
若是你的Web 应用程序或网站要确保残疾人特别是那些使用屏幕阅读器的人都能访问,那么在使用鼠标事件时就要格外当心。前面提到过,能够经过键盘上的回车键来触发click 事件,但其余鼠标事件却没法经过键盘来触发。为此,咱们不建议使用click 以外的其余鼠标事件来展现功能或引起代码执行。由于这样会给盲人或视障用户形成极大不便。如下是在使用鼠标事件时应当注意的几个易访问性问题。
遵守以上提示能够极大地提高残疾人在访问你的Web 应用程序或网站时的易访问性。
要了解如何在网页中实现无障碍访问的内容,请访问www.webaim.org 和http://yaccessibilityblog.com/。