如何在滚动DIV元素时防止页面滚动?

我已经审查和testing了各种function,以防止身体在div内滚动的能力,并结合了一个应该工作的function。

$('.scrollable').mouseenter(function() { $('body').bind('mousewheel DOMMouseScroll', function() { return false; }); $(this).bind('mousewheel DOMMouseScroll', function() { return true; }); }); $('.scrollable').mouseleave(function() { $('body').bind('mousewheel DOMMouseScroll', function() { return true; }); }); 
  • 这是停止所有滚动,因为我想滚动仍然可以在容器内
  • 这也没有停用鼠标离开

任何想法,或更好的方式来做到这一点?

更新2:我的解决scheme是基于禁用浏览器的本地滚动(当游标在DIV中),然后用JavaScript手动滚动DIV(通过设置.scrollTop属性)。 一个替代和IMO更好的方法是只有select性地禁用浏览器的滚动,以防止页面滚动,而不是DIV滚动。 看看Rudie的答案,下面演示了这个解决scheme。


干得好:

 $( '.scrollable' ).on( 'mousewheel DOMMouseScroll', function ( e ) { var e0 = e.originalEvent, delta = e0.wheelDelta || -e0.detail; this.scrollTop += ( delta < 0 ? 1 : -1 ) * 30; e.preventDefault(); }); 

现场演示: https : //jsbin.com/howojuq/edit?js,output

所以你手动设置滚动位置,然后防止默认的行为(这将是滚动的DIV或整个网页)。

更新1:正如Chris在下面的评论中指出的那样,在更新版本的jQuery中,增量信息嵌套在.originalEvent对象中,即jQuery不再将其暴露在自定义事件对象中,我们必须从本地Event对象。

如果你不关心与旧IE版本的兼容性(<8),你可以制作一个自定义的jQuery插件,然后在溢出元素上调用它。

这个解决scheme比一个Vimeas提出的方法有优势,因为它不会覆盖滚动行为 – 只是在适当的时候阻止它。

 $.fn.isolatedScroll = function() { this.bind('mousewheel DOMMouseScroll', function (e) { var delta = e.wheelDelta || (e.originalEvent && e.originalEvent.wheelDelta) || -e.detail, bottomOverflow = this.scrollTop + $(this).outerHeight() - this.scrollHeight >= 0, topOverflow = this.scrollTop <= 0; if ((delta < 0 && bottomOverflow) || (delta > 0 && topOverflow)) { e.preventDefault(); } }); return this; }; $('.scrollable').isolatedScroll(); 

我认为有时候可以取消mousescroll事件: http : //jsfiddle.net/rudiedirkx/F8qSq/show/

 $elem.on('mousewheel DOMMouseScroll', function(e) { var d = e.originalEvent.wheelDelta || -e.originalEvent.detail, dir = d > 0 ? 'up' : 'down', stop = (dir == 'up' && this.scrollTop == 0) || (dir == 'down' && this.scrollTop == this.scrollHeight-this.offsetHeight); stop && e.preventDefault(); }); 

在事件处理程序中,您需要知道:

  • 滚动方向
    var d = e.wheelDelta || -e.detail var d = e.wheelDelta || -e.detail Chrome使用var d = e.wheelDelta || -e.detail ,Firefox使用相反的detail
  • 滚动位置
    scrollTop顶部, scrollHeight - scrollTop - offsetHeight底部

如果你是

  • 向上滚动, top = 0 ,或
  • 向下滚动, bottom = 0

取消事件: e.preventDefault() (甚至可能是e.stopPropagation() )。

我认为最好不要覆盖浏览器的滚动行为。 只适用时取消。

这可能不是完美的xbrowser,但它不是很难。 也许Mac的双滚动方向是棘手的,但…

看看这是否有助于你:

演示: jsfiddle

 $('#notscroll').bind('mousewheel', function() { return false }); 

编辑:

尝试这个:

  $("body").delegate("div.scrollable","mouseover mouseout", function(e){ if(e.type === "mouseover"){ $('body').bind('mousewheel',function(){ return false; }); }else if(e.type === "mouseout"){ $('body').bind('mousewheel',function(){ return true; }); } }); 

在上面的解决scheme中,有一点关于Firefox的错误。 在Firefox中,“DOMMouseScroll”事件没有e.detail属性,为了得到这个属性,你应该写下如下的'e.originalEvent.detail'。

这是一个适用于Firefox的工作解决scheme:

 $.fn.isolatedScroll = function() { this.on('mousewheel DOMMouseScroll', function (e) { var delta = e.wheelDelta || (e.originalEvent && e.originalEvent.wheelDelta) || -e.originalEvent.detail, bottomOverflow = (this.scrollTop + $(this).outerHeight() - this.scrollHeight) >= 0, topOverflow = this.scrollTop <= 0; if ((delta < 0 && bottomOverflow) || (delta > 0 && topOverflow)) { e.preventDefault(); } }); return this; }; 

一个不太好的解决scheme,在我看来是设置隐藏在身体上,当你滑过滚动div。 这将防止身体滚动,但会发生不必要的“跳跃”效果。 以下解决scheme可以解决这个问题

 jQuery(".scrollable") .mouseenter(function(e) { // get body width now var body_width = jQuery("body").width(); // set overflow hidden on body. this will prevent it scrolling jQuery("body").css("overflow", "hidden"); // get new body width. no scrollbar now, so it will be bigger var new_body_width = jQuery("body").width(); // set the difference between new width and old width as padding to prevent jumps jQuery("body").css("padding-right", (new_body_width - body_width)+"px"); }) .mouseleave(function(e) { jQuery("body").css({ overflow: "auto", padding-right: "0px" }); }) 

如果需要,你可以使你的代码更加智能化。 例如,你可以testing主体是否已经有了填充,如果是的话,添加新的填充。

这是我在应用程序中使用的解决scheme。

我禁用了身体溢出,并把整个网站的HTML内的容器div的。 网站容器溢出,因此用户可以按预期滚动页面。

然后我创build了一个覆盖整个网站的具有更高z-索引的兄弟分区(#Prevent)。 由于#Prevent具有较高的Z-index,因此它与网站容器重叠。 当#Prevent可见时,鼠标不再徘徊网站容器,因此滚动是不可能的。

你当然可以在标记中放置另一个div,比如你的模态,它的z-index比#Prevent要高。 这使您可以创build不受滚动问题影响的popup窗口。

这个解决scheme更好,因为它不隐藏滚动条(跳跃的影响)。 它不需要事件监听器,而且很容易实现。 它适用于所有的浏览器,但IE7和8你必须玩(取决于你的具体代码)。

HTML

 <body> <div id="YourModal" style="display:none;"></div> <div id="Prevent" style="display:none;"></div> <div id="WebsiteContainer"> <div id="Website"> website goes here... </div> </div> </body> 

CSS

 body { overflow: hidden; } #YourModal { z-index:200; /* modal styles here */ } #Prevent { z-index:100; position:absolute; left:0px; height:100%; width:100%; background:transparent; } #WebsiteContainer { z-index:50; overflow:auto; position: absolute; height:100%; width:100%; } #Website { position:relative; } 

jQuery的/ JS

 function PreventScroll(A) { switch (A) { case 'on': $('#Prevent').show(); break; case 'off': $('#Prevent').hide(); break; } } 

禁用/启用滚动

 PreventScroll('on'); // prevent scrolling PreventScroll('off'); // allow scrolling 

这里没有一个简单的解决scheme,不会破坏浏览器原生滚动(这是:没有人为/丑陋的滚动):

 var scrollable = document.querySelector('.scrollable'); scrollable.addEventListener('wheel', function(event) { var deltaY = event.deltaY; var contentHeight = scrollable.scrollHeight; var visibleHeight = scrollable.offsetHeight; var scrollTop = scrollable.scrollTop; if (scrollTop === 0 && deltaY < 0) event.preventDefault(); else if (visibleHeight + scrollTop === contentHeight && deltaY > 0) event.preventDefault(); }); 

现场演示: http : //jsfiddle.net/ibcaliax/bwmzfmq7/4/

我需要将这个事件添加到可能有滚动条的多个元素。 对于没有滚动条的情况,主滚动条不能正常工作。 所以我对@Šime代码进行了一些小改动,如下所示:

 $( '.scrollable' ).on( 'mousewheel DOMMouseScroll', function ( e ) { if($(this).prop('scrollHeight') > $(this).height()) { var e0 = e.originalEvent, delta = e0.wheelDelta || -e0.detail; this.scrollTop += ( delta < 0 ? 1 : -1 ) * 30; e.preventDefault(); } }); 

现在,只有带滚动条的元素才能防止主滚动开始停止。

纯粹的JavaScript版本的Vidas的答案, el$是您正在滚动的飞机的DOM节点。

 function onlyScrollElement(event, el$) { var delta = event.wheelDelta || -event.detail; el$.scrollTop += (delta < 0 ? 1 : -1) * 10; event.preventDefault(); } 

确保你不附加甚至多次! 这里是一个例子,

 var ul$ = document.getElementById('yo-list'); // IE9, Chrome, Safari, Opera ul$.removeEventListener('mousewheel', onlyScrollElement); ul$.addEventListener('mousewheel', onlyScrollElement); // Firefox ul$.removeEventListener('DOMMouseScroll', onlyScrollElement); ul$.addEventListener('DOMMouseScroll', onlyScrollElement); 

谨慎的话 ,这个函数需要是一个常量,如果你每次在附加函数之前重新初始化函数,也就是说。 var func = function (...) removeEventListener将不起作用。

你可以不用JavaScript来做到这一点。 你可以在div上设置风格position: fixedoverflow-y: auto 。 您可能需要通过设置其z-index (如果它们重叠)来使其中一个高于另一个。

这是CodePen的一个基本例子 。