首页 > 代码库 > 浅谈鼠标滚轮事件
浅谈鼠标滚轮事件
现在的网页设计越来越高大上,效果越来越炫酷毙。一些浏览器的默认东西都被纷纷嫌弃,取而代之的是各种酷炫拽的模拟组件。就好像之前说过的视差滚动,又好像各种小清新的模拟滚动条,都有共同的事件:滚轮事件。
正如大家所知道的那样,jquery框架默认是不支持鼠标中轮滚轮事件的。要实现不同浏览器之间的滚轮事件,我们不能不说一下这个js组件了:jquery.mousewheel.js。
什么都不说,先上源码:
/*! Copyright (c) 2013 Brandon Aaron (http://brandon.aaron.sh) * Licensed under the MIT License (LICENSE.txt). * * Version: 3.1.11 * * Requires: jQuery 1.2.2+ */ (function (factory) { if ( typeof define === 'function' && define.amd ) { // AMD. Register as an anonymous module. define(['jquery'], factory); } else if (typeof exports === 'object') { // Node/CommonJS style for Browserify module.exports = factory; } else { // Browser globals factory(jQuery); } }(function ($) { var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'], toBind = ( 'onwheel' in document || document.documentMode >= 9 ) ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'], slice = Array.prototype.slice, nullLowestDeltaTimeout, lowestDelta; if ( $.event.fixHooks ) { for ( var i = toFix.length; i; ) { $.event.fixHooks[ toFix[--i] ] = $.event.mouseHooks; } } var special = $.event.special.mousewheel = { version: '3.1.11', setup: function() { if ( this.addEventListener ) { for ( var i = toBind.length; i; ) { this.addEventListener( toBind[--i], handler, false ); } } else { this.onmousewheel = handler; } // Store the line height and page height for this particular element $.data(this, 'mousewheel-line-height', special.getLineHeight(this)); $.data(this, 'mousewheel-page-height', special.getPageHeight(this)); }, teardown: function() { if ( this.removeEventListener ) { for ( var i = toBind.length; i; ) { this.removeEventListener( toBind[--i], handler, false ); } } else { this.onmousewheel = null; } // Clean up the data we added to the element $.removeData(this, 'mousewheel-line-height'); $.removeData(this, 'mousewheel-page-height'); }, getLineHeight: function(elem) { var $parent = $(elem)['offsetParent' in $.fn ? 'offsetParent' : 'parent'](); if (!$parent.length) { $parent = $('body'); } return parseInt($parent.css('fontSize'), 10); }, getPageHeight: function(elem) { return $(elem).height(); }, settings: { adjustOldDeltas: true, // see shouldAdjustOldDeltas() below normalizeOffset: true // calls getBoundingClientRect for each event } }; $.fn.extend({ mousewheel: function(fn) { return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel'); }, unmousewheel: function(fn) { return this.unbind('mousewheel', fn); } }); function handler(event) { var orgEvent = event || window.event, args = slice.call(arguments, 1), delta = 0, deltaX = 0, deltaY = 0, absDelta = 0, offsetX = 0, offsetY = 0; event = $.event.fix(orgEvent); event.type = 'mousewheel'; // Old school scrollwheel delta if ( 'detail' in orgEvent ) { deltaY = orgEvent.detail * -1; } if ( 'wheelDelta' in orgEvent ) { deltaY = orgEvent.wheelDelta; } if ( 'wheelDeltaY' in orgEvent ) { deltaY = orgEvent.wheelDeltaY; } if ( 'wheelDeltaX' in orgEvent ) { deltaX = orgEvent.wheelDeltaX * -1; } // Firefox < 17 horizontal scrolling related to DOMMouseScroll event if ( 'axis' in orgEvent && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) { deltaX = deltaY * -1; deltaY = 0; } // Set delta to be deltaY or deltaX if deltaY is 0 for backwards compatabilitiy delta = deltaY === 0 ? deltaX : deltaY; // New school wheel delta (wheel event) if ( 'deltaY' in orgEvent ) { deltaY = orgEvent.deltaY * -1; delta = deltaY; } if ( 'deltaX' in orgEvent ) { deltaX = orgEvent.deltaX; if ( deltaY === 0 ) { delta = deltaX * -1; } } // No change actually happened, no reason to go any further if ( deltaY === 0 && deltaX === 0 ) { return; } // Need to convert lines and pages to pixels if we aren't already in pixels // There are three delta modes: // * deltaMode 0 is by pixels, nothing to do // * deltaMode 1 is by lines // * deltaMode 2 is by pages if ( orgEvent.deltaMode === 1 ) { var lineHeight = $.data(this, 'mousewheel-line-height'); delta *= lineHeight; deltaY *= lineHeight; deltaX *= lineHeight; } else if ( orgEvent.deltaMode === 2 ) { var pageHeight = $.data(this, 'mousewheel-page-height'); delta *= pageHeight; deltaY *= pageHeight; deltaX *= pageHeight; } // Store lowest absolute delta to normalize the delta values absDelta = Math.max( Math.abs(deltaY), Math.abs(deltaX) ); if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; // Adjust older deltas if necessary if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) { lowestDelta /= 40; } } // Adjust older deltas if necessary if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) { // Divide all the things by 40! delta /= 40; deltaX /= 40; deltaY /= 40; } // Get a whole, normalized value for the deltas delta = Math[ delta >= 1 ? 'floor' : 'ceil' ](delta / lowestDelta); deltaX = Math[ deltaX >= 1 ? 'floor' : 'ceil' ](deltaX / lowestDelta); deltaY = Math[ deltaY >= 1 ? 'floor' : 'ceil' ](deltaY / lowestDelta); // Normalise offsetX and offsetY properties if ( special.settings.normalizeOffset && this.getBoundingClientRect ) { var boundingRect = this.getBoundingClientRect(); offsetX = event.clientX - boundingRect.left; offsetY = event.clientY - boundingRect.top; } // Add information to the event object event.deltaX = deltaX; event.deltaY = deltaY; event.deltaFactor = lowestDelta; event.offsetX = offsetX; event.offsetY = offsetY; // Go ahead and set deltaMode to 0 since we converted to pixels // Although this is a little odd since we overwrite the deltaX/Y // properties with normalized deltas. event.deltaMode = 0; // Add event and delta to the front of the arguments args.unshift(event, delta, deltaX, deltaY); // Clearout lowestDelta after sometime to better // handle multiple device types that give different // a different lowestDelta // Ex: trackpad = 3 and mouse wheel = 120 if (nullLowestDeltaTimeout) { clearTimeout(nullLowestDeltaTimeout); } nullLowestDeltaTimeout = setTimeout(nullLowestDelta, 200); return ($.event.dispatch || $.event.handle).apply(this, args); } function nullLowestDelta() { lowestDelta = null; } function shouldAdjustOldDeltas(orgEvent, absDelta) { // If this is an older event and the delta is divisable by 120, // then we are assuming that the browser is treating this as an // older mouse wheel event and that we should divide the deltas // by 40 to try and get a more usable deltaFactor. // Side note, this actually impacts the reported scroll distance // in older browsers and can cause scrolling to be slower than native. // Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false. return special.settings.adjustOldDeltas && orgEvent.type === 'mousewheel' && absDelta % 120 === 0; } }));
js插件里面主要的2个函数就是mousewheel和unmousewheel。
调用方式也是多种多样,
例如你可以这样:
$('.demo').mousewheel(function(){ //to do something }); $('.demo').bind('mousewheel', function(){ //to do something });
下面来说说它的参数。
mousewheel事件的参数除了第一个参数event外,还会接收第二个参数delta。通过参数delta可以获取鼠标滚轮的方向和速度。如果delta的值是负的,那么滚轮就是向下滚动,正的就是向上。
举个例子:
var gao=document.documentElement.clientHeight,h,wflag=true,fh=0,uph=0,yundong=true; $('.mod-step').css('height',gao); $('.mod-step').bind('mousewheel', function(event, delta) { if(yundong==true){ yundong=false; var index=parseInt($(this).index('.mod-step'))+1; h=gao*index; if(delta < 0){ //如果是向下滚动就干什么事情 //to do something }else{ //如果是向上滚动就干什么事情 //to do something }
ps:看看参数如何调用就行,其他代码的细节可以忽略。
接下来看看不同浏览器返回的不同的值。
先看谷歌浏览器的:向下滚动时,
然后是火狐的,向下滚动时,
然后是ie11的,向下滚动:
然后是ie9的,向下滚动:
接下来就是ie8,向下滚动的:
总结:各种浏览器返回的数值基本都不一样。所以如果要用具体数字判断,还是不科学的,但是用是否大于0,还是靠谱的。
当中的差异,如果有兴趣的可以去张鑫旭的博客看看。附上网址:http://www.zhangxinxu.com/wordpress/2013/04/js-mousewheel-dommousescroll-event/
滚轮事件的各种运用,我就不多说了,提供几个demo给大家去看看,真心好用。
http://joelb.me/scrollpath/
http://manos.malihu.gr/jquery-custom-content-scroller/
http://noraesae.github.io/perfect-scrollbar/
总结:虽然不是什么大插件,但是填补了jQuery没有滚轮事件的缺陷,简单实用。
Author: Alone
Antroduction: 高级前端开发工程师
Sign: 人生没有失败,只有没到的成功。
浅谈鼠标滚轮事件