Ruby's Louvre

每天学习一点点算法

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

javascript滚轮事件总结

滚轮事件是一个非常有用的事件,在翻页或放大时,通常都用到它。但它在各浏览器中实现兼容是相对比较困难的,号称最标准的FF,用了一个私有实现DOMMouseScroll,而使用mousewheel的其他浏览器或多或少有点bug。我们先看各浏览器对它的支持程度吧。

IEfirefoxsafarichromeopera
window对象falsetruetruetruetrue
文档对象truetruetruetruetrue
元素节点truetruetruetruetrue

接着我们看一下,如何在火狐中实现滚轮事件的事件分派:

window.addEventListener("DOMMouseScroll",function(event){
  alert(event.type)
  alert(event.clientY)
},false);
var event = document.createEvent("MouseEvent");
//为了证明分派成功,特意将其clientY设为90
event.initMouseEvent("DOMMouseScroll",true, null, window,0,0,0,0,90,false,false,false,false,0,null);
window.dispatchEvent(event)

我们可以看到虽然其他标准浏览器也支持这个名为DOMMouseScroll的事件发派,但当我们手动滚动鼠标滑轮时,也只有FF有反应,弹出两个alert。对于其他标准浏览器,我们改用mousewheel试试。

window.addEventListener("mousewheel",function(event){
  alert(event.type)
  alert(event.clientX)
},false);
var event = document.createEvent("MouseEvent");
//为了证明分派成功,特意将其clientX设为120
event.initMouseEvent("mousewheel",true, null, window,0,0,0,120,0,false,false,false,false,0,null);
window.dispatchEvent(event)

这个在FF的以外的标准浏览器见效,FF只能实现事件分派,不能实现手动触发。可以说,如果非原浏览器原生支持的事件类型,addEventListener是一概不理会的。

对于IE就简单得多了,它没有初始化事件的步骤,你也无法设置其属性,因为那是只读的,但可以设置自定义属性。

  window.onload = function(){
    document.attachEvent("onmousewheel",function(){
      var e = window.event;
      alert(e)
      alert(e.type)
      alert(e.aa)
    });
  var event = document.createEventObject();
  event.aa = "司徒正美"
 
  document.fireEvent("onmousewheel",event)
}

说完事件分派,就到事件绑定部分。虽然现在只有FF在用DOMMouseScroll,但考虑到未来FF改用的mousewheel的可能,我们还是写个程序来检测其需要的事件类型吧。最后我们还要在回调函数中修正其滚动属性:

  • IE6-11,chrome的属性名为wheelDelta,ff那边为detail,现在统一为delta。
  • IE6-11等往上滚一圈为120,往下滚一圈为-120。ff那边往上滚一圈为-3,往下滚一圈为3,但opera9x系列却实现错误,与IE滚动方向一致,不过10后又修复。
  • safari早期版本,wheelDelta会出现浮点数的情况,我们需要自行取整。
function addEvent(el, type, callback, useCapture  ){
      if(el.dispatchEvent){//w3c方式优先
          el.addEventListener( type, callback, !!useCapture  );
      }else {
          el.attachEvent( "on"+type, callback );
      }
      return callback;//返回callback方便卸载时用
  }
  var wheel = function(obj,callback){
      var wheelType = "mousewheel"
      try{
          document.createEvent("MouseScrollEvents")
          wheelType = "DOMMouseScroll"
      }catch(e){}
      addEvent(obj, wheelType,function(event){
          if ("wheelDelta" in event){//统一为±120,其中正数表示为向上滚动,负数表示向下滚动
              var delta = event.wheelDelta
              //opera 9x系列的滚动方向与IE保持一致,10后修正
              if( window.opera && opera.version() < 10 )
                  delta = -delta;
              //由于事件对象的原有属性是只读,我们只能通过添加一个私有属性delta来解决兼容问题
              event.delta = Math.round(delta) /120; //修正safari的浮点 bug
          }else if( "detail" in event ){
              event.wheelDelta = -event.detail * 40//为FF添加更大众化的wheelDelta
              event.delta = event.wheelDelta /120  //添加私有的delta
          }
          callback.call(obj,event);//修正IE的this指向
      });
  }

用法:

wheel(document,function(e){
  alert(e.delta)
});

Event property Applies to event: Up 1 click Up 2 clicks Down 1 click Down 2 clicks
e.wheelDelta

Supported in Non FF browsers

onmousewheel and in non FF browsers 120 240 -120 -240
e.detail

Supported in FF and Opera

DOMMouseScroll and in FF (as of FF3.x) -1 -2 1 2

FF官网还给出一个兼容方案:

// creates a global "addwheelListener" method
// example: addWheelListener( elem, function( e ) { console.log( e.deltaY ); e.preventDefault(); } );
(function(window,document) {
  
    var prefix = "", _addEventListener, onwheel, support;
  
    // detect event model
    if ( window.addEventListener ) {
        _addEventListener = "addEventListener";
    } else {
        _addEventListener = "attachEvent";
        prefix = "on";
    }
  
    // detect available wheel event
    if ( document.onmousewheel !== undefined ) {
        // Webkit and IE support at least "mousewheel"
        support = "mousewheel"
    }
    try {
        // Modern browsers support "wheel"
        WheelEvent("wheel");
        support = "wheel";
    } catch (e) {}
    if ( !support ) {
        // let's assume that remaining browsers are older Firefox
        support = "DOMMouseScroll";
    }
  
    window.addWheelListener = function( elem, callback, useCapture ) {
        _addWheelListener( elem, support, callback, useCapture );
  
        // handle MozMousePixelScroll in older Firefox
        if( support == "DOMMouseScroll" ) {
            _addWheelListener( elem, "MozMousePixelScroll", callback, useCapture );
        }
    };
  
    function _addWheelListener( elem, eventName, callback, useCapture ) {
        elem[ _addEventListener ]( prefix + eventName, support == "wheel" ? callback : function( originalEvent ) {
            !originalEvent && ( originalEvent = window.event );
  
            // create a normalized event object
            var event = {
                // keep a ref to the original event object
                originalEvent: originalEvent,
                target: originalEvent.target || originalEvent.srcElement,
                type: "wheel",
                deltaMode: originalEvent.type == "MozMousePixelScroll" ? 0 : 1,
                deltaX: 0,
                delatZ: 0,
                preventDefault: function() {
                    originalEvent.preventDefault ?
                        originalEvent.preventDefault() :
                        originalEvent.returnValue = false;
                }
            };
              
            // calculate deltaY (and deltaX) according to the event
            if ( support == "mousewheel" ) {
                event.deltaY = - 1/40 * originalEvent.wheelDelta;
                // Webkit also support wheelDeltaX
                originalEvent.wheelDeltaX && ( event.deltaX = - 1/40 * originalEvent.wheelDeltaX );
            } else {
                event.deltaY = originalEvent.detail;
            }
  
            // it's time to fire the callback
            return callback( event );
  
        }, useCapture || false );
    }
  
})(window,document);
firefox chrome IE11 safari5.1.7
wheel
deltaX 0
deltaY 3(向下)
deltaZ 0
                    
deltaX: -0
deltaY: 100
deltaZ: 0
detail: 0
wheelDelta: -120
wheelDeltaX: 0
wheelDeltaY: -120
                    
deltaX: 0
deltaY: 52.5
deltaZ: 0
detail: 0
                    
                    
mousewheel
type竟然是wheel
deltaX: -0
deltaY: 100
deltaZ: 0
detail: 0
wheelDelta: -120
wheelDeltaX: 0
wheelDeltaY: -120
                    
wheelDelta:-120
wheelDelta: -120
wheelDeltaX: 0
wheelDeltaY: -120
                    
DOMMouseScroll detail:3(向下)

如果您觉得此文有帮助,可以打赏点钱给我支付宝1669866773@qq.com ,或扫描二维码

posted on   司徒正美  阅读(17297)  评论(12编辑  收藏  举报

编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
点击右上角即可分享
微信分享提示