Firefox + jQuery 鼠标滚轮滚动事件 Bug

24

更新:根据 David 提供的建议,以下是有效的修复方法:

替换

    $('.scrollMe').bind("mousewheel DOMMouseScroll", ...) 

使用

    $('.scrollMe').bind("mousewheel DOMMouseScroll MozMousePixelScroll", ...) 

原帖

Firefox 16.0.2(最新版本)绑定“鼠标滚轮/ DOMMouseScroll”事件时出现问题。 当鼠标指针位于我所定位的div上方时,使用鼠标滚轮滚动会导致窗口也滚动-而我显然不希望这样。

我尝试了添加多种方法来停止传播等,但似乎没有效果。

Javascript代码:

    $(document).ready(function() {
            $('.scrollMe').bind("mousewheel DOMMouseScroll", function(e) {
                e.stopImmediatePropagation();
                e.stopPropagation();
                e.preventDefault();

                var delta = parseInt(e.originalEvent.wheelDelta || -e.originalEvent.detail);

                $(this).empty();    
                return false;
            });
    });

请点击下方的jsFiddle链接查看实际效果。在示例页面中,只需将鼠标指针放置在带有红色框的div内部,并使用鼠标滚轮。Firefox第一次会滚动父窗口(出人意料),而其他浏览器则不会。

jsFiddle代码示例

奇怪的是,Firefox在绑定元素上触发事件后不会再次发生这种行为,这意味着它停止滚动页面。但是,如果你手动滚动页面并再次尝试,它会再次重复这种行为。

我还在IE9和Chrome中进行了测试,但没有发现这个问题(意味着它们不会意外地滚动窗口),所以我猜测这是Firefox特有的(也禁用了firefox中的每个插件等)。

这是Firefox的一个真正的bug吗(如果是,是否有跨浏览器的hack可以解决)?或者,如果你知道任何其他解决方案来实现捕获鼠标滚轮事件而不会滚动页面的窗口,请随时回答!


请使用 event.originalEvent.deltaY 替代 event.originalEvent.wheelDelta 来获取 Firefox 中的滚动方向。 - CoffeJunky
救了我的一天!点赞! - Ariful Haque
4个回答

21

我用我的FF 16.01 OSX触控板无法复现这个错误(样例代码能正常工作),但我知道还有另一个仅适用于Mozilla的事件叫做MozMousePixelScroll。你可能也想尝试使用它。

在MDN上还有更多信息:https://developer.mozilla.org/zh-CN/docs/DOM/DOM_event_reference/DOMMouseScroll

顺带一提,我认为只需要使用e.preventDefault()来停止默认操作就足够了,没有必要停止事件传播(除非还有其他只存在于IE的错误)。


将MozMousePixelScroll添加到需要监听的事件列表中确实解决了问题。我需要再多看一下官方文档! - L2Eer
根据链接页面所述,使用“wheel”事件而不是“mousewheel”事件可以取消它并防止其默认行为。 - challet
+L2Eer,你能发一下你用的代码吗?我一直在遇到和你一样的问题,一个代码示例会非常有帮助。谢谢。 - www139

5

阅读https://developer.mozilla.org/zh-CN/docs/DOM/DOM_event_reference/DOMMouseScroll,看起来MozMousePixelScroll和DOMMouseScroll适用于Firefox 16或更早的版本。 对于Firefox >17,请使用wheel事件。

$(document).ready(function() {
        $('.scrollMe').bind("wheel mousewheel", function(e) {
            e.preventDefault();

            var delta = parseInt(e.originalEvent.wheelDelta || -e.originalEvent.detail);

            $(this).empty();    
            return false;
        });
});

1
这个问题的答案中,我找到了最多浏览器兼容解决方案:

如何检测滚动方向

 $('#elem').on( 'DOMMouseScroll mousewheel', function ( event ) { 
    if( event.originalEvent.detail > 0 || event.originalEvent.wheelDelta < 0 ) { //alternative options for wheelData: wheelDeltaX & wheelDeltaY
        //scroll down
        console.log('Down');
      } else {
        //scroll up
        console.log('Up');
      }
      //prevent page fom scrolling
      return false;
    });

0

这个答案是一个跨浏览器解决方案,适用于Chrome、Firefox和iExplorer

var handlerMousewheel = function(){
  $(".item").on("wheel mousewheel", function(event) {
   event.preventDefault();
    var deltaY = event.originalEvent.deltaY;
    var wheelDeltaY = event.originalEvent.wheelDeltaY;

     if( deltaY == 100 && wheelDeltaY == -120 || deltaY > 0 && wheelDeltaY == undefined ) {
        $(".wrapper").animate({"margin-left":"0%"},{duration:100});
     }else if(deltaY == -100 && wheelDeltaY == 120 || deltaY < 0 && wheelDeltaY == undefined){
         $(".wrapper").animate({"margin-left":"50%"},{duration:100});
     }
 
  });
 }
  handlerMousewheel();
.container{
  display:block;
  width:100%;
  height:200px;
  overflow-x:hidden;
  overflow-y:scroll;
  background-color: grey;  
}
.wrapper{
  display:block;
  overflow:hidden;
  background-color:#a3cfef;
  padding: 2%;
  width:50%;
  margin:0 auto;
}
.item{
  width:100%;
  height:50px;
  margin:2px 0;
  display:block;
  overflow:hidden;
  border:3px solid #ad08a6;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
  <div class="wrapper">
    <div class="item"></div>    
    <div class="item"></div>    
    <div class="item"></div>    
    <div class="item"></div>    
    <div class="item"></div>    
    <div class="item"></div>    
    <div class="item"></div>    
  </div>
</div>

https://jsfiddle.net/rrubio/ncLjgwy0/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接