本文详细解析了主流浏览器对鼠标滚轮事件的不同实现机制,包括IE的onmousewheel与wheelDelta、Firefox的DOMMouseScroll与detail属性,以及Chrome和Opera的混合支持。通过代码示例展示了如何统一各浏览器返回值,解决正负号差异与数值标准化问题,并提供未来DOM3标准中WheelEvent的简要介绍。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>Mouse Wheel Data</title> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> <style> .slider { width:50px; height:180px; background:#eee; padding:10px 0; cursor:n-resize; } .slider-slot { width:16px; margin:0 auto; height:180px; background:#eee; border:1px solid gray; border-color:#999 white white #999; position:relative; } .slider-trigger { width:14px; height:18px; font:1px/0 arial; border:1px solid gray; border-color:white #999 #999 white; background:#ccc; position:absolute; } .slider-trigger b { display:block; margin:1px 3px; border-top:1px solid #999; border-bottom:1px solid white; } </style> </head> <body> <h2>文本框增加/减少值</h2> <div><input type="text" id="txt" value="1440" /><span id="warn">文本框获得焦点后滚动鼠标滚轮</span></div> <h2>鼠标滚动缩放图片</h2> <div><img src="/upload/201005/20100531231516458.jpg" /></div> <h2>鼠标滚动控制滑块移动</h2> <div class="slider" id="slider"> <div class="slider-slot"> <div class="slider-trigger" id="sliderTrigger"> <strong></strong> <strong></strong> <strong></strong> <strong></strong> <strong></strong> </div> </div> </div> </body> </html> [Ctrl+A 全选 注:引入外部Js需再刷新一下页面才能执行]
各浏览器滚轮事件兼容现状
首先梳理不同浏览器对鼠标滚轮事件的兼容支持情况。
IE 6,7,8
在IE浏览器中,通过注册 onmousewheel 事件来监听滚轮动作。
获取滚动数值时,使用 event.wheelDelta 属性。
其滚动步长固定为 120。
数值方向规定为:向下滚动为负值,向上滚动为正值。
当鼠标指针保持在同一坐标且持续不间断滚动时,wheelDelta 的值会按步长累加。
例如连续向下滚动两次,数值可能变为 -240 或 -360。
Firefox 3.5
Firefox 提供了两个相关事件:MozMousePixelScroll 和 DOMMouseScroll。需要注意的是,这两个事件无法通过 element.onDOMMouseScroll 方式注册,必须使用 addEventListener 进行监听。
Firefox 不支持 event.wheelDelta,而是采用 event.detail 属性来获取滚动信息,这一设计与其他浏览器存在显著差异。
event.detail 原本用于记录在鼠标坐标不变的情况下,事件触发的次数。
在触发 DOMMouseScroll 事件时,detail 的值通常为 3 或 -3。
然而,Firefox 的取值方向与 IE 相反:向上滚动为负值,向下滚动为正值。在实际代码中需要进行统一处理以消除这种差异。
之所以说 detail 值“通常”是 3 和 -3,是因为如果用户按住 Ctrl、Alt 或 Shift 键的同时滑动滚轮,detail 的值会变为 1 和 -1。
此外,如果按住其他修饰键,正值有时甚至会变为 6,导致数值波动较大。
总体而言,Firefox 在此方面的实现显得较为混乱。
MozMousePixelScroll 据 Mozilla 官方说明,是一个与 DOMMouseScroll 类似但精度更高(精确到像素)的事件。
但该事件的 detail 返回值非常特殊:默认值为 51 和 -51,若按住 Ctrl、Alt 或 Shift 键,则变为 ±17。鉴于其数值规律难以预测,本文决定忽略此事件,不予使用。
Chrome 的行为与 IE 基本一致,但考虑到横向滚轮设备的需求,Chrome 额外增加了两个鼠标轴变量以分别获取水平和垂直方向的滚动值。
Chrome 监听的事件仍为 onmousewheel。
垂直滚动值通过 wheelDelta {number} 获取。
水平滚动值通过 wheelDeltaX {number} 获取。
垂直滚动值也可通过 wheelDeltaY {number} 获取。
Opera 浏览器则兼具两者特性:它既支持 detail 属性(取值同样为 3 和 -3),也支持 wheelDelta,且在表现上相对一致。
Opera 监听的事件为 onmousewheel。
detail 属性返回 {number} 类型的数值。
wheelDelta 属性同样返回 {number} 类型的数值。
统一滚轮数值的处理策略
理论上,我们可以选择 Firefox 支持的 event.detail 或 IE 等浏览器支持的 event.wheelDelta 中的一个,并将另一个通过计算转换为统一格式。
但实际上,我们主要需要知道滚动的方向(向上或向下)。
为了简化后续应用中的运算,我们将所有浏览器的返回值统一标准化为 +1 和 -1。
对于 IE 和 Chrome,直接将 wheelDelta 除以 120 即可得到标准化结果。
Opera 同时支持 wheelDelta 和 detail,但 detail 属性不具备 wheelDelta 在同一位置连续滚动时累加的特性。
因此,代码逻辑优先判断 wheelDelta 是否存在;若存在则直接使用 wheelDelta,否则再使用 detail。
由于 Firefox 的 detail 值受键盘按键干扰较大,我们需要对其进行过滤处理。
首先对 detail 值与 3 进行取模运算(value % 3)。
如果取模结果为 0,说明该值是 3 的倍数,此时将 value 除以 3 后返回(确保返回值为 +1 或 -1)。
如果取模结果不为 0,说明该值已经是 1 或 -1,直接返回原值即可。
最后,由于 Firefox 的返回值规则是“向上为负、向下为正”,这与常规习惯相反,因此需要在计算结果前添加负号以反转正负方向。
综上所述,Firefox 对滚轮事件的支持确实存在不少令人困惑的地方。
经过上述详细分析,实际处理滚轮事件的代码非常简洁。
代码如下:
function getWheelValue( e )
{
e = e||event;
return ( e.wheelDelta ? e.wheelDelta/120 : -( e.detail%3 == 0 ? e.detail : e.detail/3 ) );
} 未来 DOM3 滚轮事件标准
最后简要介绍未来滚轮事件的标准与 API。
在 DOM3 Event 规范中,
滚轮事件的处理变得更加复杂,同时也支持更多功能。
注册的事件名称并未改变,依然称为 mousewheel。
规范专门新增了两个滚轮事件对象类型。
MouseWheelEvent
WheelEvents
新标准支持 x、y、z 三个轴向的滚轮值,这使得处理逻辑更加复杂。
感兴趣的开发者可以查阅相关文档。
http://www.w3.org/TR/DOM-Level-3-Events/#events-mousewheelevents