如何在滚动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: fixed
和overflow-y: auto
。 您可能需要通过设置其z-index
(如果它们重叠)来使其中一个高于另一个。
这是CodePen的一个基本例子 。