我已经审查并测试了各种功能,以防止身体在div内部滚动,并结合了一个应该起作用的功能。
$('.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;
});
});
任何想法或更好的方法吗?
答案 0 :(得分:160)
更新2:我的解决方案基于完全禁用浏览器的本机滚动(当光标在DIV内时),然后使用JavaScript手动滚动DIV(通过设置其.scrollTop
属性)。替代和IMO更好的方法是仅选择性地禁用浏览器的滚动以防止页面滚动,而不是DIV滚动。查看下面的Rudie的答案,该答案演示了此解决方案。
你走了:
$( '.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中,delta信息嵌套在.originalEvent
对象中,即jQuery不会在其自定义中公开它事件对象,我们必须从本机Event对象中检索它。
答案 1 :(得分:28)
如果您不关心与旧IE版本(&lt; 8)的兼容性,您可以制作一个自定义jQuery插件,然后在溢出元素上调用它。
这个解决方案比一个提出的ŠimeVidas有一个优势,因为它不会覆盖滚动行为 - 它只是在适当时阻止它。
$.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();
答案 2 :(得分:21)
我认为有时可以取消mousescroll事件:http://jsfiddle.net/rudiedirkx/F8qSq/show/
$elem.on('wheel', function(e) {
var d = e.originalEvent.deltaY,
dir = d < 0 ? 'up' : 'down',
stop = (dir == 'up' && this.scrollTop == 0) ||
(dir == 'down' && this.scrollTop == this.scrollHeight-this.offsetHeight);
stop && e.preventDefault();
});
在事件处理程序中,您需要知道:
d = e.originalEvent.deltaY, dir = d < 0 ? 'up' : 'down'
因为正数表示向下滚动scrollTop
,底部为scrollHeight - scrollTop - offsetHeight
如果你是
top = 0
或bottom = 0
,取消活动:e.preventDefault()
(甚至可能是e.stopPropagation()
)。
我认为最好不要覆盖浏览器的滚动行为。仅在适用时取消。
这可能不是完美的xbrowser,但它不是很难。也许Mac的双滚动方向虽然很棘手......
答案 3 :(得分:3)
看看这对你有帮助:
演示: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;
});
}
});
答案 4 :(得分:3)
一个不太讨厌的解决方案,在我看来,当你将鼠标悬停在可滚动的div上时,设置隐藏在身体上的溢出。这将阻止身体滚动,但会发生不必要的“跳跃”效果。以下解决方案可以解决这个问题:
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"
});
})
如果需要,您可以使代码更智能。例如,您可以测试正文是否已有填充,如果是,则将新填充添加到该填充。
答案 5 :(得分:3)
在上面的解决方案中,Firefox有一点错误。在Firefox“DOMMouseScroll”事件中没有e.detail属性,要获取此属性,您应该编写以下'e.originalEvent.detail'。
这是Firefox的可行解决方案:
$.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;
};
答案 6 :(得分:3)
这里有一个没有jQuery的简单解决方案,它不会破坏浏览器本机滚动(这是:没有人工/丑陋的滚动):
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();
});
答案 7 :(得分:2)
这是我在应用程序中使用的解决方案。
我禁用了身体溢出并将整个网站html放在容器div中。网站容器已溢出,因此用户可按预期滚动页面。
然后我创建了一个兄弟div(#Prevent),它具有覆盖整个网站的更高的z-index。由于#Prevent具有更高的z-index,因此它与网站容器重叠。当#Prevent可见时,鼠标不再悬停在网站容器上,因此无法滚动。
你当然可以在标记中放置另一个div,例如你的模态,其z-index比#Prevent高。这允许您创建不受滚动问题影响的弹出窗口。
此解决方案更好,因为它不会隐藏滚动条(跳跃效果)。它不需要事件监听器,并且易于实现。它可以在所有浏览器中使用,但使用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
答案 8 :(得分:1)
我需要将此事件添加到可能具有滚动条的多个元素中。对于没有滚动条的情况,主滚动条不能正常工作。所以我对@Š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();
}
});
现在,只有带滚动条的元素才能阻止主滚动开始停止。
答案 9 :(得分:1)
在CSS属性下方使用
overscroll-behavior: contain;
到子元素
答案 10 :(得分:0)
Vidas答案的纯javascript版本,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
无效。
答案 11 :(得分:0)
这里是用于防止在滚动特定div时阻止父级滚动的插件,并且有很多选项可以使用。
在此处查看:
https://github.com/MohammadYounes/jquery-scrollLock
用法
通过JavaScript触发滚动锁定:
$('#target').scrollLock();
通过标记触发滚动锁定:
<!-- HTML -->
<div data-scrollLock
data-strict='true'
data-selector='.child'
data-animation='{"top":"top locked","bottom":"bottom locked"}'
data-keyboard='{"tabindex":0}'
data-unblock='.inner'>
...
</div>
<!-- JavaScript -->
<script type="text/javascript">
$('[data-scrollLock]').scrollLock()
</script>
查看Demo
答案 12 :(得分:0)
如果您认为用户不会对明显的变化产生负面的体验,请提供此解决方案。当鼠标悬停在目标div之上时,我只是将身体的溢出类别更改为隐藏。然后当鼠标离开时,将主体的div更改为隐藏溢出。
我个人并不认为它看起来很糟糕,我的代码可以使用toggle使其更整洁,并且在用户不知情的情况下实现这种效果有明显的好处。因此,这可能是最后的解决办法。
//listen mouse on and mouse off for the button
pxMenu.addEventListener("mouseover", toggleA1);
pxOptContainer.addEventListener("mouseout", toggleA2);
//show / hide the pixel option menu
function toggleA1(){
pxOptContainer.style.display = "flex";
body.style.overflow = "hidden";
}
function toggleA2(){
pxOptContainer.style.display = "none";
body.style.overflow = "hidden scroll";
}
答案 13 :(得分:0)
您需要的只是
e.preventDefault();
关于子元素。