我有一个小的“浮动工具箱”-一个div的位置:fixed;溢出:汽车。 工作得很好。

但是当滚动到盒子里面(用鼠标滚轮)并到达底部或顶部时,父元素“接管”“滚动请求”:工具箱后面的文档滚动。 -这是恼人的,而不是用户“要求”。

我正在使用jQuery,并认为我可以用event.stoppropagation()停止这种行为: $(" #工具箱”)。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();
        }
    }
});

当前回答

我能找到的最佳解决方案是监听窗口上的滚动事件,并在子div可见时将scrollTop设置为前一个scrollTop。

prevScrollPos = 0
$(window).scroll (ev) ->
    if $('#mydiv').is(':visible')
        document.body.scrollTop = prevScrollPos
    else
        prevScrollPos = document.body.scrollTop

如果触发大量滚动事件,子div的背景中会有闪烁,所以这可以进行调整,但它几乎不会被注意到,对于我的用例来说已经足够了。

其他回答

M.K.在他的回答中提供了一个很棒的插件。插件可以在这里找到。然而,为了完整起见,我认为把它放在AngularJS的一个答案中是一个好主意。

Start by injecting the bower or npm (whichever is preferred) bower install jquery-scrollLock --save npm install jquery-scroll-lock --save Add the following directive. I am choosing to add it as an attribute (function() { 'use strict'; angular .module('app') .directive('isolateScrolling', isolateScrolling); function isolateScrolling() { return { restrict: 'A', link: function(sc, elem, attrs) { $('.scroll-container').scrollLock(); } } } })(); And the important piece the plugin fails to document in their website is the HTML structure that it must follow. <div class="scroll-container locked"> <div class="scrollable" isolate-scrolling> ... whatever ... </div> </div>

属性isolation -scrolling必须包含可滚动类,而且它都需要在滚动容器类或任何您选择的类中,并且锁定类必须级联。

在这个线程中给出的所有解决方案都没有提到一个现有的和本地的方法来解决这个问题,而不需要重新排序DOM和/或使用事件阻止技巧。但是有一个很好的理由:这种方法是专有的-并且只能在MS web平台上使用。引用MSDN:

-ms-scroll- chainingproperty -指定当用户在操作过程中达到滚动限制时发生的滚动行为。属性值: chained -初始值。当用户在操作期间达到滚动限制时,最近的可滚动父元素开始滚动。没有反弹效果显示。 none -当用户在操作过程中碰到滚动限制时,会显示一个反弹效果。

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

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

现在有好消息了,各位!从Chrome 63开始,我们终于有了针对基于blink的平台的原生疗法——这就是Chrome(显然)和Android WebView(很快)。

引用介绍文章:

The overscroll-behavior property is a new CSS feature that controls the behavior of what happens when you over-scroll a container (including the page itself). You can use it to cancel scroll chaining, disable/customize the pull-to-refresh action, disable rubberbanding effects on iOS (when Safari implements overscroll-behavior), and more.[...] The property takes three possible values: auto - Default. Scrolls that originate on the element may propagate to ancestor elements. contain - prevents scroll chaining. Scrolls do not propagate to ancestors but local effects within the node are shown. For example, the overscroll glow effect on Android or the rubberbanding effect on iOS which notifies the user when they've hit a scroll boundary. Note: using overscroll-behavior: contain on the html element prevents overscroll navigation actions. none - same as contain but it also prevents overscroll effects within the node itself (e.g. Android overscroll glow or iOS rubberbanding). [...] The best part is that using overscroll-behavior does not adversely affect page performance like the hacks mentioned in the intro!

下面是这个功能的实际情况。这里是相应的CSS模块文档。

更新:Firefox从59版开始加入这个俱乐部,MS Edge预计将在18版实现这个功能。这是相应的犬科用法。

更新2:现在(2022年10月)Safari正式加入了这个俱乐部:从16.0版本开始,overscroll行为不再落后于功能标志。

不要使用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;
}

在这里玩演示。

编辑:代码依赖的例子

对于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的平滑滚动就会打败这个黑客。

我能找到的最佳解决方案是监听窗口上的滚动事件,并在子div可见时将scrollTop设置为前一个scrollTop。

prevScrollPos = 0
$(window).scroll (ev) ->
    if $('#mydiv').is(':visible')
        document.body.scrollTop = prevScrollPos
    else
        prevScrollPos = document.body.scrollTop

如果触发大量滚动事件,子div的背景中会有闪烁,所以这可以进行调整,但它几乎不会被注意到,对于我的用例来说已经足够了。