我有一个小“浮动工具箱” - 一个带有 position:fixed; overflow:auto
的 div。工作得很好。
但是当在该框内滚动(使用鼠标滚轮)并到达底部或顶部时,父元素“接管”“滚动请求”:工具箱后面的文档滚动。 - 这很烦人,而不是用户“要求”的。
我正在使用 jQuery,并认为我可以使用 event.stoppropagation() 停止这种行为:
$("#toolBox").scroll( function(event){ event.stoppropagation() });
它确实进入了函数,但仍然会发生传播(文档滚动) - 在 SO(和谷歌)上搜索这个主题非常困难,所以我不得不问:如何防止滚动事件的传播/冒泡?
编辑:
感谢 amustill 的工作解决方案(以及此处的鼠标滚轮插件的 Brandon Aaron:
https://github.com/brandonaaron/jquery-mousewheel/raw/master/jquery.mousewheel.js
$(".ToolPage").bind('mousewheel', function(e, d)
var t = $(this);
if (d > 0 && t.scrollTop() === 0) {
e.preventDefault();
}
else {
if (d < 0 && (t.scrollTop() == t.get(0).scrollHeight - t.innerHeight())) {
e.preventDefault();
}
}
});
overflow:hidden
,当鼠标悬停在工具箱中时,或保存文档 scrollTop,并在工具箱期间反复将其强制在文档上(很好) 。滚动()...
为了完整起见,我添加了这个答案,因为 @amustill 接受的答案没有正确解决 Internet Explorer 中的问题。有关详细信息,请参阅 my original post 中的评论。此外,这个解决方案不需要任何插件——只需要 jQuery。
实质上,代码通过处理 mousewheel
事件来工作。每个这样的事件都包含一个 wheelDelta
,它等于要将可滚动区域移动到的 px
的数量。如果此值为 >0
,那么我们正在滚动 up
。如果 wheelDelta
是 <0
,那么我们正在滚动 down
。
FireFox:FireFox 使用 DOMMouseScroll
作为事件并填充 originalEvent.detail
,其 +/-
与上述相反。它通常返回 3
的间隔,而其他浏览器以 120
的间隔返回滚动(至少在我的机器上)。为了纠正,我们简单地检测它并乘以 -40
来归一化。
如果 <div>
的可滚动区域已经位于顶部或底部最大位置,则 @amustill's answer 会取消事件。但是,在 delta
大于剩余可滚动空间的情况下,Internet Explorer 会忽略取消的事件。
换句话说,如果您有一个包含 500px
可滚动内容的 200px
高 <div>
,并且当前 scrollTop
是 400
,则一个告诉浏览器进一步滚动 120px
的 mousewheel
事件将导致 <div>
和 <body>
滚动,因为 400
+ 120
> 500
。
所以——要解决这个问题,我们必须做一些稍微不同的事情,如下所示:
必要的 jQuery
代码是:
$(document).on('DOMMouseScroll mousewheel', '.Scrollable', function(ev) {
var $this = $(this),
scrollTop = this.scrollTop,
scrollHeight = this.scrollHeight,
height = $this.innerHeight(),
delta = (ev.type == 'DOMMouseScroll' ?
ev.originalEvent.detail * -40 :
ev.originalEvent.wheelDelta),
up = delta > 0;
var prevent = function() {
ev.stopPropagation();
ev.preventDefault();
ev.returnValue = false;
return false;
}
if (!up && -delta > scrollHeight - height - scrollTop) {
// Scrolling down, but this will take us past the bottom.
$this.scrollTop(scrollHeight);
return prevent();
} else if (up && delta > scrollTop) {
// Scrolling up, but this will take us past the top.
$this.scrollTop(0);
return prevent();
}
});
本质上,此代码取消任何会创建不需要的边缘条件的滚动事件,然后使用 jQuery 将 <div>
的 scrollTop
设置为最大值或最小值,具体取决于 mousewheel
事件请求的方向.
由于该事件在任何一种情况下都被完全取消,它根本不会传播到 body
,因此解决了 IE 以及所有其他浏览器中的问题。
我也提出了一个working example on jsFiddle。
这个线程中给出的所有解决方案都没有提到现有的 - 和本机 - 解决这个问题的方法,而无需重新排序 DOM 和/或使用事件预防技巧。但有一个很好的理由:这种方式是专有的 - 并且仅在 MS Web 平台上可用。引用MSDN:
-ms-scroll-chaining 属性 - 指定当用户在操作期间达到滚动限制时发生的滚动行为。属性值:chained - 初始值。当用户在操作期间达到滚动限制时,最近的可滚动父元素开始滚动。没有显示反弹效果。 none - 当用户在操作过程中达到滚动限制时会显示弹跳效果。
当然,此属性仅在 IE10+/Edge 上受支持。不过,这里有一个 telling quote:
为了让您了解防止滚动链接的流行程度,根据我的快速 http-archive 搜索,“-ms-scroll-chaining: none”在 0.4% 的前 300K 页面中使用,尽管功能有限且仅支持IE/边缘。
现在好消息,大家!从 Chrome 63 开始,我们终于有了针对基于 Blink 的平台的原生解决方案——这就是 Chrome(显然)和 Android WebView(很快)。
overscroll-behavior 属性是一个新的 CSS 特性,它控制过度滚动容器(包括页面本身)时发生的行为。您可以使用它来取消滚动链接、禁用/自定义下拉刷新操作、禁用 iOS 上的橡皮筋效果(当 Safari 实现过度滚动行为时)等等。[...] 该属性采用三个可能的值:auto - 默认。源自元素的滚动可能会传播到祖先元素。包含 - 防止滚动链接。滚动不会传播到祖先,但会显示节点内的局部效果。例如,Android 上的过度滚动发光效果或 iOS 上的橡皮筋效果,当用户到达滚动边界时会通知用户。注意:在 html 元素上使用 overscroll-behavior: contains 可以防止过度滚动导航操作。 none - 与 contains 相同,但它也防止节点本身内的过度滚动效果(例如,Android 过度滚动发光或 iOS 橡皮筋)。 [...] 最好的部分是使用 overscroll-behavior 不会像介绍中提到的黑客那样对页面性能产生不利影响!
这是feature in action。这里是对应的 CSS Module document。
更新: Firefox 从 59 版开始加入俱乐部,预计 MS Edge 将在 18 版中实现此功能。这里是对应的 caniusage。
overscroll-behavior
。
可以使用 Brandon Aaron 的 Mousewheel plugin。
这是一个演示:http://jsbin.com/jivutakama/edit?html,js,output
$(function() {
var toolbox = $('#toolbox'),
height = toolbox.height(),
scrollHeight = toolbox.get(0).scrollHeight;
toolbox.bind('mousewheel', function(e, d) {
if((this.scrollTop === (scrollHeight - height) && d < 0) || (this.scrollTop === 0 && d > 0)) {
e.preventDefault();
}
});
});
我知道这是一个很老的问题,但由于这是谷歌的顶级结果之一......我不得不以某种方式取消没有 jQuery 的滚动冒泡,这段代码对我有用:
function preventDefault(e) {
e = e || window.event;
if (e.preventDefault)
e.preventDefault();
e.returnValue = false;
}
document.getElementById('a').onmousewheel = function(e) {
document.getElementById('a').scrollTop -= e. wheelDeltaY;
preventDefault(e);
}
对于 AngularJS,我定义了以下指令:
module.directive('isolateScrolling', function () {
return {
restrict: 'A',
link: function (scope, element, attr) {
element.bind('DOMMouseScroll', function (e) {
if (e.detail > 0 && this.clientHeight + this.scrollTop == this.scrollHeight) {
this.scrollTop = this.scrollHeight - this.clientHeight;
e.stopPropagation();
e.preventDefault();
return false;
}
else if (e.detail < 0 && this.scrollTop <= 0) {
this.scrollTop = 0;
e.stopPropagation();
e.preventDefault();
return false;
}
});
element.bind('mousewheel', function (e) {
if (e.deltaY > 0 && this.clientHeight + this.scrollTop >= this.scrollHeight) {
this.scrollTop = this.scrollHeight - this.clientHeight;
e.stopPropagation();
e.preventDefault();
return false;
}
else if (e.deltaY < 0 && this.scrollTop <= 0) {
this.scrollTop = 0;
e.stopPropagation();
e.preventDefault();
return false;
}
return true;
});
}
};
});
然后将其添加到可滚动元素(下拉菜单 ul):
<div class="dropdown">
<button type="button" class="btn dropdown-toggle">Rename <span class="caret"></span></button>
<ul class="dropdown-menu" isolate-scrolling>
<li ng-repeat="s in savedSettings | objectToArray | orderBy:'name' track by s.name">
<a ng-click="renameSettings(s.name)">{{s.name}}</a>
</li>
</ul>
</div>
在 Chrome 和 Firefox 上测试。当在滚动区域的顶部或底部附近(但不是在)附近进行较大的鼠标滚轮移动时,Chrome 的平滑滚动可以解决此问题。
<ul>
到达底部时页面继续滚动。
DOMMouseScroll
后也不起作用。
有很多这样的问题,有很多答案,但我找不到不涉及事件、脚本、插件等的令人满意的解决方案。我想直接用 HTML 和 CSS 来解决。我终于找到了一个可行的解决方案,尽管它涉及重组标记以打破事件链。
1.基本问题
应用于模态元素的滚动输入(即:鼠标滚轮)将溢出到祖先元素并沿相同方向滚动它,如果某些这样的元素是可滚动的:
(所有示例均应在桌面分辨率上查看)
https://jsfiddle.net/ybkbg26c/5/
HTML:
<div id="parent">
<div id="modal">
This text is pretty long here. Hope fully, we will get some scroll bars.
</div>
</div>
CSS:
#modal {
position: absolute;
height: 100px;
width: 100px;
top: 20%;
left: 20%;
overflow-y: scroll;
}
#parent {
height: 4000px;
}
2.模态滚动没有父滚动
祖先最终滚动的原因是滚动事件冒泡并且链上的某些元素能够处理它。阻止这种情况的一种方法是确保链上的所有元素都不知道如何处理滚动。在我们的示例中,我们可以重构树以将模式移出父元素。出于晦涩的原因,仅保留父级和模态 DOM 同级是不够的;父元素必须由另一个建立新的堆叠上下文的元素包裹。围绕父级的绝对定位的包装器可以解决问题。
我们得到的结果是,只要 modal 接收到滚动事件,该事件就不会冒泡到“父”元素。
通常应该可以重新设计 DOM 树以支持这种行为,而不会影响最终用户看到的内容。
https://jsfiddle.net/0bqq31Lv/3/
HTML:
<div id="context">
<div id="parent">
</div>
</div>
<div id="modal">
This text is pretty long here. Hope fully, we will get some scroll bars.
</div>
CSS(仅限新):
#context {
position: absolute;
overflow-y: scroll;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
3. 启动时除了模态外,其他地方都不能滚动
上面的解决方案仍然允许父级接收滚动事件,只要它们不被模态窗口拦截(即,如果在光标不在模态窗口上方时由鼠标滚轮触发)。这有时是不可取的,我们可能希望在模式启动时禁止所有背景滚动。为此,我们需要在模态框后面插入一个跨越整个视口的额外堆叠上下文。我们可以通过显示一个绝对定位的叠加层来做到这一点,如果需要,它可以是完全透明的(但不是 visibility:hidden
)。
https://jsfiddle.net/0bqq31Lv/2/
HTML:
<div id="context">
<div id="parent">
</div>
</div>
<div id="overlay">
</div>
<div id="modal">
This text is pretty long here. Hope fully, we will get some scroll bars.
</div>
CSS(#2之上的新):
#overlay {
background-color: transparent;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
这是一个纯 JavaScript 版本:
function scroll(e) {
var delta = (e.type === "mousewheel") ? e.wheelDelta : e.detail * -40;
if (delta < 0 && (this.scrollHeight - this.offsetHeight - this.scrollTop) <= 0) {
this.scrollTop = this.scrollHeight;
e.preventDefault();
} else if (delta > 0 && delta > this.scrollTop) {
this.scrollTop = 0;
e.preventDefault();
}
}
document.querySelectorAll(".scroller").addEventListener("mousewheel", scroll);
document.querySelectorAll(".scroller").addEventListener("DOMMouseScroll", scroll);
作为变体,为了避免 scroll
或 mousewheel
处理的性能问题,您可以使用如下代码:
CSS:
body.noscroll {
overflow: hidden;
}
.scrollable {
max-height: 200px;
overflow-y: scroll;
border: 1px solid #ccc;
}
html:
<div class="scrollable">
...A bunch of items to make the div scroll...
</div>
...A bunch of text to make the body scroll...
js:
var $document = $(document),
$body = $('body'),
$scrolable = $('.scrollable');
$scrolable.on({
'mouseenter': function () {
// add hack class to prevent workspace scroll when scroll outside
$body.addClass('noscroll');
},
'mouseleave': function () {
// remove hack class to allow scroll
$body.removeClass('noscroll');
}
});
工作示例:http://jsbin.com/damuwinarata/4
Angular JS 指令
我不得不包装一个角度指令。以下是此处其他答案的混搭。在 Chrome 和 Internet Explorer 11 上测试。
var app = angular.module('myApp');
app.directive("preventParentScroll", function () {
return {
restrict: "A",
scope: false,
link: function (scope, elm, attr) {
elm.bind('mousewheel', onMouseWheel);
function onMouseWheel(e) {
elm[0].scrollTop -= (e.wheelDeltaY || (e.originalEvent && (e.originalEvent.wheelDeltaY || e.originalEvent.wheelDelta)) || e.wheelDelta || 0);
e.stopPropagation();
e.preventDefault();
e.returnValue = false;
}
}
}
});
用法
<div prevent-parent-scroll>
...
</div>
希望这对通过 Google 搜索到达这里的下一个人有所帮助。
e.originalEvent
是为了支持 IE
将本机元素滚动属性与鼠标滚轮插件中的 delta 值一起使用:
$elem.on('mousewheel', function (e, delta) {
// Restricts mouse scrolling to the scrolling range of this element.
if (
this.scrollTop < 1 && delta > 0 ||
(this.clientHeight + this.scrollTop) === this.scrollHeight && delta < 0
) {
e.preventDefault();
}
});
如果有人仍在为此寻找解决方案,以下插件可以完成这项工作 http://mohammadyounes.github.io/jquery-scrollLock/
它完全解决了在给定容器内锁定鼠标滚轮滚动的问题,防止它传播到父元素。
它不会改变滚轮滚动速度,不会影响用户体验。并且无论操作系统鼠标滚轮垂直滚动速度如何,您都会获得相同的行为(在 Windows 上,它可以设置为一个屏幕或一条线,每个凹槽最多 100 行)。
演示:http://mohammadyounes.github.io/jquery-scrollLock/example/
来源:https://github.com/MohammadYounes/jquery-scrollLock
你可以用 CSS 实现这个结果,即
.isolate-scrolling {
overscroll-behavior: contain;
}
如果您的鼠标将子元素留给父元素,这只会滚动父容器。
amustill 作为淘汰处理程序的回答:
ko.bindingHandlers.preventParentScroll = {
init: function (element, valueAccessor, allBindingsAccessor, context) {
$(element).mousewheel(function (e, d) {
var t = $(this);
if (d > 0 && t.scrollTop() === 0) {
e.preventDefault();
}
else {
if (d < 0 && (t.scrollTop() == t.get(0).scrollHeight - t.innerHeight())) {
e.preventDefault();
}
}
});
}
};
上面的方法不是很自然,经过一番谷歌搜索后,我找到了一个更好的解决方案,并且不需要 jQuery。参见 [1] 和演示 [2]。
var element = document.getElementById('uf-notice-ul'); var isMacWebkit = (navigator.userAgent.indexOf("Macintosh") !== -1 && navigator.userAgent.indexOf("WebKit") !== -1); var isFirefox = (navigator.userAgent.indexOf("firefox") !== -1); element.onwheel = wheelHandler; // 未来的浏览器 element.onmousewheel = wheelHandler; // 当前大多数浏览器 if (isFirefox) { element.scrollTop = 0; element.addEventListener("DOMMouseScroll", wheelHandler, false); } // 防止滚动父元素 function wheelHandler(event) { var e = event ||窗口.事件; // 标准或 IE 事件对象 // 从事件对象中提取旋转量,查找 // 滚轮事件对象、鼠标滚轮事件对象 //(在其 2D 和 1D 形式中)和 Firefox DOMMouseScroll 的属性事件。 // 缩放增量,使向屏幕的一次“点击”为 30 像素。 // 如果未来的浏览器同时为同一个事件触发“wheel”和“mousewheel”,我们最终会在这里重复计算。但是,希望 // 取消滚轮事件将阻止鼠标滚轮的生成。变量 deltaX = e.deltaX * -30 || // 车轮事件 e.wheelDeltaX / 4 || // 鼠标滚轮 0; // 属性未定义 var deltaY = e.deltaY * -30 || // 车轮事件 e.wheelDeltaY / 4 || // Webkit 中的鼠标滚轮事件 (e.wheelDeltaY === undefined && // 如果没有 2D 属性则 e.wheelDelta / 4) || // 使用一维轮属性 e.detail * -10 || // Firefox DOMMouseScroll 事件 0; // 属性未定义 // 大多数浏览器在每次鼠标滚轮点击时生成一个 delta 120 的事件。 // 然而,在 Mac 上,鼠标滚轮似乎对速度敏感,并且 // delta 值通常是 120 的更大倍数, // 至少对于 Apple Mouse。使用浏览器测试来解决这个问题。 if (isMacWebkit) { deltaX /= 30; deltaY /= 30; } e.currentTarget.scrollTop -= deltaY; // 如果我们曾经在(未来版本的)Firefox 中获得鼠标滚轮或滚轮事件,那么我们就不再需要 DOMMouseScroll。 if (isFirefox && e.type !== "DOMMouseScroll") { element.removeEventListener("DOMMouseScroll", wheelHandler, false); } // 不要让这个事件冒泡。防止任何默认操作。 // 这会阻止浏览器使用鼠标滚轮事件来滚动 // 文档。希望在滚轮事件上调用 preventDefault() // 也会阻止为相同的旋转生成鼠标滚轮事件。 if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); e.cancelBubble =真; // IE 事件 e.returnValue = false; // IE 事件返回 false; }
[1] https://dimakuzmich.wordpress.com/2013/07/16/prevent-scrolling-of-parent-element-with-javascript/
[2] http://jsfiddle.net/dima_k/5mPkB/1/
这实际上适用于 AngularJS。在 Chrome 和 Firefox 上测试。
.directive('stopScroll', function () {
return {
restrict: 'A',
link: function (scope, element, attr) {
element.bind('mousewheel', function (e) {
var $this = $(this),
scrollTop = this.scrollTop,
scrollHeight = this.scrollHeight,
height = $this.height(),
delta = (e.type == 'DOMMouseScroll' ?
e.originalEvent.detail * -40 :
e.originalEvent.wheelDelta),
up = delta > 0;
var prevent = function() {
e.stopPropagation();
e.preventDefault();
e.returnValue = false;
return false;
};
if (!up && -delta > scrollHeight - height - scrollTop) {
// Scrolling down, but this will take us past the bottom.
$this.scrollTop(scrollHeight);
return prevent();
} else if (up && delta > scrollTop) {
// Scrolling up, but this will take us past the top.
$this.scrollTop(0);
return prevent();
}
});
}
};
})
我的 jQuery 插件:
$('.child').dontScrollParent();
$.fn.dontScrollParent = function()
{
this.bind('mousewheel DOMMouseScroll',function(e)
{
var delta = e.originalEvent.wheelDelta || -e.originalEvent.detail;
if (delta > 0 && $(this).scrollTop() <= 0)
return false;
if (delta < 0 && $(this).scrollTop() >= this.scrollHeight - $(this).height())
return false;
return true;
});
}
我有类似的情况,这就是我解决它的方法:我所有的可滚动元素都使类可滚动。
$(document).on('wheel', '.scrollable', function(evt) {
var offsetTop = this.scrollTop + parseInt(evt.originalEvent.deltaY, 10);
var offsetBottom = this.scrollHeight - this.getBoundingClientRect().height - offsetTop;
if (offsetTop < 0 || offsetBottom < 0) {
evt.preventDefault();
} else {
evt.stopImmediatePropagation();
}
});
stopImmediatePropagation() 确保不从可滚动子区域滚动父可滚动区域。
这是它的普通 JS 实现:http://jsbin.com/lugim/2/edit?js,output
新的网络开发人员在这里。这在 IE 和 Chrome 上对我来说都是一种魅力。
static preventScrollPropagation(e: HTMLElement) {
e.onmousewheel = (ev) => {
var preventScroll = false;
var isScrollingDown = ev.wheelDelta < 0;
if (isScrollingDown) {
var isAtBottom = e.scrollTop + e.clientHeight == e.scrollHeight;
if (isAtBottom) {
preventScroll = true;
}
} else {
var isAtTop = e.scrollTop == 0;
if (isAtTop) {
preventScroll = true;
}
}
if (preventScroll) {
ev.preventDefault();
}
}
}
不要让行数欺骗了你,这很简单 - 只是为了可读性有点冗长(自我记录代码 ftw 对吗?)
另外我应该提一下,这里的语言是 TypeScript,但与往常一样,将其转换为 JS 很简单。
对于那些使用 MooTools 的人,这里是等效的代码:
'mousewheel': function(event){
var height = this.getSize().y;
height -= 2; // Not sure why I need this bodge
if ((this.scrollTop === (this.scrollHeight - height) && event.wheel < 0) ||
(this.scrollTop === 0 && event.wheel > 0)) {
event.preventDefault();
}
请记住,我和其他人一样,必须将值调整几个 px,这就是 height -= 2 的用途。
基本上主要区别在于,在 MooTools 中,增量信息来自 event.wheel,而不是传递给事件的额外参数。
此外,如果我将此代码绑定到任何东西,我也会遇到问题(绑定函数的 event.target.scrollHeight 不等于非绑定函数的 this.scrollHeight)
希望这对某人有帮助,就像这篇文章对我有帮助一样;)
getSize()
不考虑边框(在您的情况下,边框在顶部和底部都是 1px)。
查看 Leland Kwong's 代码。
基本思路是将wheeling事件绑定到子元素,然后使用子元素的原生javascript属性scrollHeight
和jquery属性outerHeight
检测滚动结束,然后return false
到wheeling事件以防止任何滚动。
var scrollableDist,curScrollPos,wheelEvent,dY;
$('#child-element').on('wheel', function(e){
scrollableDist = $(this)[0].scrollHeight - $(this).outerHeight();
curScrollPos = $(this).scrollTop();
wheelEvent = e.originalEvent;
dY = wheelEvent.deltaY;
if ((dY>0 && curScrollPos >= scrollableDist) ||
(dY<0 && curScrollPos <= 0)) {
return false;
}
});
我从所选的库中将其 yoinked:https://github.com/harvesthq/chosen/blob/master/coffee/chosen.jquery.coffee
function preventParentScroll(evt) {
var delta = evt.deltaY || -evt.wheelDelta || (evt && evt.detail)
if (delta) {
evt.preventDefault()
if (evt.type == 'DOMMouseScroll') {
delta = delta * 40
}
fakeTable.scrollTop = delta + fakeTable.scrollTop
}
}
var el = document.getElementById('some-id')
el.addEventListener('mousewheel', preventParentScroll)
el.addEventListener('DOMMouseScroll', preventParentScroll)
这对我有用。
具有模拟 Internet Explorer 自然滚动功能的 jQuery 插件
$.fn.mousewheelStopPropagation = function(options) {
options = $.extend({
// defaults
wheelstop: null // Function
}, options);
// Compatibilities
var isMsIE = ('Microsoft Internet Explorer' === navigator.appName);
var docElt = document.documentElement,
mousewheelEventName = 'mousewheel';
if('onmousewheel' in docElt) {
mousewheelEventName = 'mousewheel';
} else if('onwheel' in docElt) {
mousewheelEventName = 'wheel';
} else if('DOMMouseScroll' in docElt) {
mousewheelEventName = 'DOMMouseScroll';
}
if(!mousewheelEventName) { return this; }
function mousewheelPrevent(event) {
event.preventDefault();
event.stopPropagation();
if('function' === typeof options.wheelstop) {
options.wheelstop(event);
}
}
return this.each(function() {
var _this = this,
$this = $(_this);
$this.on(mousewheelEventName, function(event) {
var origiEvent = event.originalEvent;
var scrollTop = _this.scrollTop,
scrollMax = _this.scrollHeight - $this.outerHeight(),
delta = -origiEvent.wheelDelta;
if(isNaN(delta)) {
delta = origiEvent.deltaY;
}
var scrollUp = delta < 0;
if((scrollUp && scrollTop <= 0) || (!scrollUp && scrollTop >= scrollMax)) {
mousewheelPrevent(event);
} else if(isMsIE) {
// Fix Internet Explorer and emulate natural scrolling
var animOpt = { duration:200, easing:'linear' };
if(scrollUp && -delta > scrollTop) {
$this.stop(true).animate({ scrollTop:0 }, animOpt);
mousewheelPrevent(event);
} else if(!scrollUp && delta > scrollMax - scrollTop) {
$this.stop(true).animate({ scrollTop:scrollMax }, animOpt);
mousewheelPrevent(event);
}
}
});
});
};
我能找到的最佳解决方案是监听窗口上的滚动事件,如果子 div 可见,则将 scrollTop 设置为前一个 scrollTop。
prevScrollPos = 0
$(window).scroll (ev) ->
if $('#mydiv').is(':visible')
document.body.scrollTop = prevScrollPos
else
prevScrollPos = document.body.scrollTop
如果您触发大量滚动事件,子 div 的背景会闪烁,因此可以对此进行调整,但几乎没有注意到它,这对于我的用例来说已经足够了。
不要在 body
上使用 overflow: hidden;
。它会自动将所有内容滚动到顶部。也不需要 JavaScript。使用 overflow: auto;
:
HTML结构
<div class="overlay">
<div class="overlay-content"></div>
</div>
<div class="background-content">
lengthy content here
</div>
造型
.overlay{
position: fixed;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
background-color: rgba(0, 0, 0, 0.8);
.overlay-content {
height: 100%;
overflow: scroll;
}
}
.background-content{
height: 100%;
overflow: auto;
}
玩演示 here。
body
上使用 overflow: hidden;
,只要它不会自动滚动到页面顶部。但是当它自动滚动到顶部时,您应该尝试在 body
上使用 overflow: auto; height: 100%
。
当鼠标悬停在可滚动元素上时,还有一个有趣的技巧可以锁定父级的 scrollTop
。这样您就不必实现自己的滚轮滚动。
这是防止文档滚动的示例,但可以针对任何元素进行调整。
scrollable.mouseenter(function ()
{
var scroll = $(document).scrollTop();
$(document).on('scroll.trap', function ()
{
if ($(document).scrollTop() != scroll) $(document).scrollTop(scroll);
});
});
scrollable.mouseleave(function ()
{
$(document).off('scroll.trap');
});
M.K. 在他的回答中提供了一个很棒的插件。插件可以在 here 中找到。但是,为了完成,我认为将它放在一个 AngularJS 的答案中是个好主意。
首先注入 bower 或 npm(以首选为准) bower install jquery-scrollLock --save npm install jquery-scroll-lock --save 添加以下指令。我选择将其添加为属性 (function() { 'use strict'; angular .module('app') .directive('isolateScrolling', isolateScrolling); function isolateScrolling() { return { restrict: 'A',链接:函数(sc,elem,attrs){ $('.scroll-container').scrollLock(); } } } })();插件未能在其网站中记录的重要部分是它必须遵循的 HTML 结构。
属性 isolate-scrolling
必须包含 scrollable
类,并且它都需要在 scroll-container
类或您选择的任何类中,并且 locked
类必须是级联的。
值得一提的是,使用 reactJS、AngularJS、VueJS 等现代框架,在处理固定位置元素时,可以轻松解决这个问题。示例是侧面板或覆盖元素。
该技术称为“门户”,这意味着应用程序中使用的组件之一,无需从您使用它的位置实际提取它,将其子组件安装在 body 元素的底部,在父母您试图避免滚动。
请注意,它不会避免滚动正文元素本身。您可以结合此技术并将您的应用程序安装在滚动 div 中以实现预期结果。
React 的 material-ui 中的示例门户实现:https://material-ui-next.com/api/portal/
有 ES 6 crossbrowser + mobile vanila js 决定:
function stopParentScroll(selector) {
let last_touch;
let MouseWheelHandler = (e, selector) => {
let delta;
if(e.deltaY)
delta = e.deltaY;
else if(e.wheelDelta)
delta = e.wheelDelta;
else if(e.changedTouches){
if(!last_touch){
last_touch = e.changedTouches[0].clientY;
}
else{
if(e.changedTouches[0].clientY > last_touch){
delta = -1;
}
else{
delta = 1;
}
}
}
let prevent = function() {
e.stopPropagation();
e.preventDefault();
e.returnValue = false;
return false;
};
if(selector.scrollTop === 0 && delta < 0){
return prevent();
}
else if(selector.scrollTop === (selector.scrollHeight - selector.clientHeight) && delta > 0){
return prevent();
}
};
selector.onwheel = e => {MouseWheelHandler(e, selector)};
selector.onmousewheel = e => {MouseWheelHandler(e, selector)};
selector.ontouchmove = e => {MouseWheelHandler(e, selector)};
}
我正在为 MooTools 寻找这个,这是第一个出现的。最初的 MooTools 示例可以向上滚动,但不能向下滚动,所以我决定写这个。
MooTools 1.4.5:http://jsfiddle.net/3MzFJ/
MooTools 1.3.2:http://jsfiddle.net/VhnD4/
MooTools 1.2.6:http://jsfiddle.net/xWrw4/
var stopScroll = function (e) {
var scrollTo = null;
if (e.event.type === 'mousewheel') {
scrollTo = (e.event.wheelDelta * -1);
} else if (e.event.type === 'DOMMouseScroll') {
scrollTo = 40 * e.event.detail;
}
if (scrollTo) {
e.preventDefault();
this.scrollTo(0, scrollTo + this.scrollTop);
}
return false;
};
用法:
(function)($){
window.addEvent('domready', function(){
$$('.scrollable').addEvents({
'mousewheel': stopScroll,
'DOMMouseScroll': stopScroll
});
});
})(document.id);
mouseweel 事件的简单解决方案:
$('.element').bind('mousewheel', function(e, d) {
console.log(this.scrollTop,this.scrollHeight,this.offsetHeight,d);
if((this.scrollTop === (this.scrollHeight - this.offsetHeight) && d < 0)
|| (this.scrollTop === 0 && d > 0)) {
e.preventDefault();
}
});
不定期副业成功案例分享
if (this.scrollHeight <= parseInt($(this).css("max-height"))) return
作为函数的第一行。