当内部元素滚动位置达到顶部/底部时,阻止父元素的滚动?

我有一个小的“浮动工具箱” - 一个带有.工作正常。position:fixed; overflow:auto

但是,当在该框内滚动(使用鼠标滚轮)并到达底部或顶部时,父元素“接管”“滚动请求”:工具箱后面的文档将滚动。
- 这很烦人,而不是用户“要求”的东西。

我正在使用jQuery,并认为我可以通过event.stoppropagation()来阻止这种行为:
$("#toolBox").scroll( function(event){ event.stoppropagation() });

它确实进入了函数,但仍然会发生传播(文档滚动)
- 在SO(和Google)上搜索这个主题非常困难,所以我不得不问:
如何防止滚动事件的传播/冒泡?

编辑:
多亏了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();
        }
    }
});

答案 1

我添加这个答案是为了完整性,因为@amustill接受的答案并不能正确解决Internet Explorer中的问题。有关详细信息,请参阅我原始帖子中的评论。此外,此解决方案不需要任何插件 - 只有jQuery。

实质上,代码通过处理事件来工作。每个此类事件都包含一个等于它将要将可滚动区域移动到的数目。如果此值为 ,则我们正在滚动 。如果 是 则 我们正在滚动 .mousewheelwheelDeltapx>0upwheelDelta<0down

FireFox:FireFox 使用作为事件,并填充 ,其与上述内容相反。它通常返回间隔 ,而其他浏览器则以 (至少在我的机器上)的间隔返回滚动。为了纠正,我们只需检测它并乘以归一化。DOMMouseScrolloriginalEvent.detail+/-3120-40

@amustill的答案的工作原理是取消事件,如果 的可滚动区域已经位于顶部或底部的最大位置。但是,Internet Explorer 会在大于剩余可滚动空间的情况下忽略已取消事件。<div>delta

换句话说,如果你有一个高的可滚动内容,而当前是,一个告诉浏览器进一步滚动的事件将导致 和 滚动,因为 + > 。200px<div>500pxscrollTop400mousewheel120px<div><body>400120500

所以 - 要解决这个问题,我们必须做一些稍微不同的事情,如下所示:

必需的代码是: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 将 的 设置为最大值或最小值,具体取决于事件请求的方向。scrollTop<div>mousewheel

由于该事件在任何一种情况下都完全取消,因此它永远不会传播到,因此可以解决IE以及所有其他浏览器中的问题。body

我还在jsFiddle上放了一个工作示例。


答案 2

此线程中给出的所有解决方案都没有提到现有的 - 和本机 - 方法来解决此问题,而无需重新排序DOM和/或使用事件预防技巧。但是有一个很好的理由:这种方式是专有的 - 并且仅在MS Web平台上可用。引用 MSDN

-ms-scroll-chaining 属性 - 指定当用户在操作期间达到滚动限制时发生的滚动行为。属性值:

链接 - 初始值。当用户在操作期间达到滚动限制时,最近的可滚动父元素开始滚动。未显示反弹效果。

none - 当用户在操作过程中达到滚动限制时,将显示反弹效果。

当然,此属性仅在 IE10+/Edge 上受支持。不过,这里有一句很有说服力的话

为了让您了解防止滚动链接的流行程度,根据我的快速http存档搜索,“-ms-scroll-chaining:none”在前300K页面中使用了0.4%,尽管功能有限并且仅在IE / Edge上受支持。

现在好消息,大家好!从Chrome 63开始,我们终于有了基于Blink的平台的原生治疗方法 - 这既是Chrome(显然)也是Android WebView(很快)。

引用介绍性文章

overscroll-behavior 属性是一项新的 CSS 功能,用于控制在过度滚动容器(包括页面本身)时发生的情况。您可以使用它来取消滚动链接,禁用/自定义拉刷新操作,禁用iOS上的橡皮筋效果(当Safari实现过度滚动行为时)等等。[...]

该属性采用三个可能的值:

自动 - 默认。源自元素的卷轴可能会传播到祖先元素。

包含 - 防止滚动链接。卷轴不会传播到祖先,但会显示节点内的局部效果。例如,Android上的过度滚动发光效果或iOS上的橡皮筋效果,当用户达到滚动边界时,它会通知用户。注意:使用 overscroll-behavior:在 html 元素上包含可防止 overscroll 导航操作。

none - 与包含相同,但它也可以防止节点本身内的过度滚动效果(例如Android过度滚动发光或iOS橡皮筋)。

[...]最好的部分是,使用overscroll行为不会像介绍中提到的黑客那样对页面性能产生不利影响!

这是此功能的实际应用。这是相应的CSS模块文档

更新:Firefox从版本59开始加入俱乐部,MS Edge预计将在版本18中实现此功能。这是相应的教规