【问题标题】:Scrolling child div scrolls the window, how do I stop that?滚动子 div 滚动窗口,我该如何停止呢?
【发布时间】:2012-04-29 23:19:03
【问题描述】:

我有一个带有滚动条的 div,当它到达末尾时,我的页面开始滚动。无论如何我可以阻止这种行为吗?

【问题讨论】:

标签: javascript html


【解决方案1】:

这是一种在 Y 轴上执行此操作的跨浏览器方法,它适用于桌面和移动设备。在 OSX 和 iOS 上测试。

var scrollArea = this.querySelector(".scroll-area");
scrollArea.addEventListener("wheel", function() {
    var scrollTop = this.scrollTop;
    var maxScroll = this.scrollHeight - this.offsetHeight;
    var deltaY = event.deltaY;
    if ( (scrollTop >= maxScroll && deltaY > 0) || (scrollTop === 0 && deltaY < 0) ) {
        event.preventDefault();
    }
}, {passive:false});

scrollArea.addEventListener("touchstart", function(event) {
    this.previousClientY = event.touches[0].clientY;
}, {passive:false});

scrollArea.addEventListener("touchmove", function(event) {
    var scrollTop = this.scrollTop;
    var maxScroll = this.scrollHeight - this.offsetHeight;
    var currentClientY = event.touches[0].clientY;
    var deltaY = this.previousClientY - currentClientY;
    if ( (scrollTop >= maxScroll && deltaY > 0) || (scrollTop === 0 && deltaY < 0) ) {
        event.preventDefault();
    }
    this.previousClientY = currentClientY;
}, {passive:false});

【讨论】:

  • 这太棒了!哇,正是我搜索的内容。它肯定需要更多的支持。
  • 此解决方案效果很好,但需要稍作调整:需要将scrollTop === maxScroll 更改为scrollTop &gt;= maxScroll。 1个案例似乎很奇怪,这是需要的
【解决方案2】:

正如here 的回答,大多数现代浏览器现在都支持overscroll-behavior: none; CSS 属性,它可以防止滚动链接。就是这样,只有一行!

【讨论】:

  • 这应该是 2020 年的正确答案。对于我的用例,最好的解决方案是 overscroll-behavior: contain;
  • 某些边缘版本不完全支持此功能。知道如何以不同的方式解决这个问题吗?
【解决方案3】:

我无法在 Chrome 和 Firefox 中获得任何答案,所以我想出了这个合并:

$someElement.on('mousewheel DOMMouseScroll', scrollProtection);

function scrollProtection(event) {
    var $this = $(this);
    event = event.originalEvent;
    var direction = (event.wheelDelta * -1) || (event.detail);
    if (direction < 0) {
        if ($this.scrollTop() <= 0) {
            return false;
        }
    } else {
        if ($this.scrollTop() + $this.innerHeight() >= $this[0].scrollHeight) {
            return false;
        }
    }
}

【讨论】:

    【解决方案4】:

    根据 ceed 的回答,这是一个允许嵌套滚动保护元素的版本。只有鼠标悬停的元素会滚动,而且滚动非常流畅。这个版本也是可重入的。它可以在同一个元素上多次使用,并且会正确删除和重新安装处理程序。

    jQuery.fn.scrollGuard = function() {
        this
            .addClass('scroll-guarding')
            .off('.scrollGuard').on('mouseenter.scrollGuard', function() {
                var $g = $(this).parent().closest('.scroll-guarding');
                $g = $g.length ? $g : $(window);
                $g[0].myCst = $g.scrollTop();
                $g[0].myCsl = $g.scrollLeft();
                $g.off("scroll.prevent").on("scroll.prevent", function() {
                    $g.scrollTop($g[0].myCst);
                    $g.scrollLeft($g[0].myCsl);
                });
            })
            .on('mouseleave.scrollGuard', function() {
                var $g = $(this).parent().closest('.scroll-guarding');
                $g = $g.length ? $g : $(window);
                $g.off("scroll.prevent");
            });
    };
    

    一种简单的使用方法是向页面中允许滚动的所有元素添加一个类,例如scroll-guard。然后使用$('.scroll-guard').scrollGuard() 保护它们。

    【讨论】:

      【解决方案5】:

      如果您输入选择器元素,这将禁用窗口上的滚动。 像魅力一样工作。

      elements = $(".selector");
      
      elements.on('mouseenter', function() {
          window.currentScrollTop = $(window).scrollTop();
          window.currentScrollLeft = $(window).scrollTop();
          $(window).on("scroll.prevent", function() {
              $(window).scrollTop(window.currentScrollTop);
              $(window).scrollLeft(window.currentScrollLeft);
          });
      });
      
      elements.on('mouseleave', function() {
          $(window).off("scroll.prevent");
      });
      

      【讨论】:

      • 这确实是一个可行的解决方案。我需要它在纯js中,所以我重新编写了它。如果有人需要它,它是here。对于仍在寻找解决方案的任何人,您应该查看我的答案below
      【解决方案6】:

      所选解决方案是一件艺术品。觉得值得一个插件....

      $.fn.scrollGuard = function() {
          return this
              .on( 'wheel', function ( e ) {
                  var event = e.originalEvent;
                  var d = event.wheelDelta || -event.detail;
                  this.scrollTop += ( d < 0 ? 1 : -1 ) * 30;
                  e.preventDefault();
              });
      };    
      

      这一直给我带来不便,与我见过的其他黑客相比,这个解决方案非常干净。很想知道它是如何工作的以及它会得到多么广泛的支持,但是为 Jeevan 和最初提出这个问题的人欢呼。顺便说一句 - stackoverflow 答案编辑器需要这个!

      更新

      我相信这更好,因为它根本不尝试操作 DOM,只是有条件地防止冒泡......

      $.fn.scrollGuard2 = function() {
        return this
          .on( 'wheel', function ( e ) {
            var $this = $(this);
            if (e.originalEvent.deltaY < 0) {
              /* scrolling up */
              return ($this.scrollTop() > 0);
            } else {
              /* scrolling down */
              return ($this.scrollTop() + $this.innerHeight() < $this[0].scrollHeight);
            }
          })
        ;
      };    
      

      在 chrome 中效果很好,比其他解决方案简单得多...让我知道它在其他地方的表现如何...

      FIDDLE

      【讨论】:

      • 添加 DOMMouseScroll 事件使其可以与 Firefox 一起使用 → jsfiddle.net/chodorowicz/egqy7mbz/1
      • 我很惊讶这没有写入 jquery。我认为其中一个要点是不必关心您使用的是什么浏览器。
      • 实际上看起来两者都已弃用...wheel event
      • 这会在我的 Macbook 上的 Chrome 中导致明显的抖动滚动。接受的解决方案没有这个问题。
      • 令人失望。这个有很多不同的版本。似乎是 ui 的一个重要方面,当它如此不直观时,这是默认行为确实令人惊讶。很明显,浏览器知道内部滚动 div 已经达到了能够将事件应用到窗口的极限,那么为什么没有可用的句柄来查询呢?
      【解决方案7】:

      找到了解决办法。

      http://jsbin.com/itajok

      这是我需要的。

      这是代码。

      http://jsbin.com/itajok/edit#javascript,html

      使用 jQuery 插件。


      因弃用通知而更新

      来自jquery-mousewheel

      添加三个参数(deltadeltaXdeltaY)的旧行为 到事件处理程序现在已弃用,稍后将被删除 发布。

      那么,现在必须使用event.deltaY

      var toolbox = $('#toolbox'),
          height = toolbox.height(),
          scrollHeight = toolbox.get(0).scrollHeight;
      
      toolbox.off("mousewheel").on("mousewheel", function (event) {
        var blockScrolling = this.scrollTop === scrollHeight - height && event.deltaY < 0 || this.scrollTop === 0 && event.deltaY > 0;
        return !blockScrolling;
      });
      

      Demo

      【讨论】:

      • 您的链接使用 github 作为 js 并中断,因为 content-type blah blah 在这里有效:jsbin.com/itajok/207
      • 这两个 jsbin 似乎都不能在 Chrome 设备模拟器和 iphone 上工作。有谁知道这是否仍然有效?
      • 您的“解决方案”仅适用于鼠标滚动事件,不适用于向上/向下翻页或箭头键。
      • 这里为什么需要“off”?
      【解决方案8】:
      $this.find('.scrollingDiv').on('mousewheel DOMMouseScroll', function (e) {
        var delta = -e.originalEvent.wheelDelta || e.originalEvent.detail;
        var scrollTop = this.scrollTop;
        if((delta < 0 && scrollTop === 0) || (delta > 0 && this.scrollHeight - this.clientHeight - scrollTop === 0)) {
          e.preventDefault();
        }
      });
      

      【讨论】:

        【解决方案9】:

        我写了解决这个问题的方法

          var div;
          div = document.getElementsByClassName('selector')[0];
        
          div.addEventListener('mousewheel', function(e) {
            if (div.clientHeight + div.scrollTop + e.deltaY >= div.scrollHeight) {
              e.preventDefault();
              div.scrollTop = div.scrollHeight;
            } else if (div.scrollTop + e.deltaY <= 0) {
              e.preventDefault();
              div.scrollTop = 0;
            }
          }, false);
        

        【讨论】:

        • 这里为数不多的解决方案之一,由于设置了溢出隐藏,页面元素不会烦人地跳跃。
        • +1 这是一个可靠的解决方案。如果你把它附加到一个可滚动的容器上,你会希望这个例子中的 div 是e.currentTarget
        • 非常干净的解决方案。谢谢
        • 在 Chrome 61.0.3163.100 和 Safari 11.0 中有效,但在 FireFox 56.0 (Mac OS El Capitan) 中无效
        • 这是最好的原生解决方案。但是,不需要为addEventListener 指定false,因为这是默认设置。此外,比较应该是简单的不等式(&gt;&lt;),而不是&gt;=&lt;=
        【解决方案10】:

        您可以通过执行类似操作来禁用整个页面的滚动,但显示滚动条!

        <div onmouseover="document.body.style.overflow='hidden'; document.body.style.position='fixed';" onmouseout="document.body.style.overflow='auto'; document.body.style.position='relative';"></div>
        

        【讨论】:

          【解决方案11】:

          如果我正确理解了您的问题,那么您希望在鼠标悬停在 div(比如说侧边栏)上时防止滚动主要内容。为此,侧边栏可能不是主要内容的滚动容器(即浏览器窗口)的子项,以防止滚动事件冒泡到其父项。

          这可能需要通过以下方式进行一些标记更改:

          <div id="wrapper"> 
              <div id="content"> 
              </div> 
          </div> 
          <div id="sidebar"> 
          </div> 
          

          查看它在 this sample fiddle 中的工作情况,并将其与 this sample fiddle 进行比较,后者的侧边栏鼠标离开行为略有不同。

          另见scroll only one particular div with browser's main scrollbar

          【讨论】:

          • 在这种情况下,侧边栏位于包装 div 之外。所以我不认为滚动会冒泡给父母
          • “这个案子”是指你的案子吗?如果不是:你是完全正确的。如果是这样:如果您的页面在 div 滚动结束时滚动,则滚动消息会冒泡到 div 父级,所以我认为您的页面和 div 不是兄弟姐妹,而是父级和子级。
          • 是的,Page 是我的 div 的父级,所以在到达末尾时,它开始滚动页面,我不想这样做。
          • 如果你不能让你的 div 成为主要内容的兄弟,那么这个问题不能单独使用 HTML+CSS 来解决。这是默认行为。
          • 我认为这是所有提供的答案中最有效的解决方案;在页面底部有良好的干净标记,为了获得所需的行为,需要更少的 CSS 和 JS hack。
          【解决方案12】:

          您可以通过执行以下操作来停用整个页面的滚动:

          <div onmouseover="document.body.style.overflow='hidden';" onmouseout="document.body.style.overflow='auto';"></div>
          

          【讨论】:

          • 很好,但是当您将鼠标悬停在 div 上时,它会使浏览器的滚动条消失。
          • @cstack 你是对的,这就是为什么 OP (Jeevan) 自己的答案更好。
          • 现在很多浏览器滚轮会随着用户移动鼠标而消失和重新出现,所以上面的评论不再是问题了。
          • 当页面嵌入到 iframe 中时,此解决方案不起作用。
          • 不是解决方案。将溢出设置为隐藏隐藏滚动条,它突然重新格式化外部元素的所有内容。此外,这假设外部元素是 body,但它可能是另一个滚动 div。
          【解决方案13】:

          您可以在 div 上使用 mouseover 事件来禁用 body 滚动条,然后使用 mouseout 事件再次激活它吗?

          例如HTML

          <div onmouseover="disableBodyScroll();" onmouseout="enableBodyScroll();">
              content
          </div>
          

          然后像这样的javascript:

          var body = document.getElementsByTagName('body')[0];
          function disableBodyScroll() {
              body.style.overflowY = 'hidden';
          }
          function enableBodyScroll() {
              body.style.overflowY = 'auto';
          }
          

          【讨论】:

          • 您也可以使用document.body
          【解决方案14】:

          如果您应用 overflow: hidden 样式,它应该会消失

          编辑:实际上我读错了你的问题,这只会隐藏滚动条,但我认为这不是你要找的。

          【讨论】:

          • 我需要两个滚动条。我在谈论行为。当我使用鼠标轨迹球滚动到 div 滚动的末尾时,它不能滚动整个页面。
          猜你喜欢
          • 1970-01-01
          • 2020-07-01
          • 1970-01-01
          • 1970-01-01
          • 2011-10-03
          • 1970-01-01
          • 2012-04-09
          • 2018-11-29
          • 1970-01-01
          相关资源
          最近更新 更多