我有一个小的“浮动工具箱”-一个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();
        }
    }
});

使用Brandon Aaron的Mousewheel插件,这是可能的。

这里是一个演示: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();
    }
  });

});

对于那些使用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.target。绑定函数的scrollHeight不等于此值。scrollHeight(非绑定)

希望这篇文章能像这篇文章帮助我一样帮助别人;)


我知道这是一个相当老的问题,但由于这是谷歌的顶级结果之一……我不得不以某种方式取消滚动冒泡没有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);
}

你可以这样尝试:

$('#element').on('shown', function(){ 
   $('body').css('overflow-y', 'hidden');
   $('body').css('margin-left', '-17px');
});

$('#element').on('hide', function(){ 
   $('body').css('overflow-y', 'scroll');
   $('body').css('margin-left', '0px');
});

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;
    });
}

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();
                }
            }
        });
    }
};

我在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);

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

本质上,代码通过处理鼠标滚轮事件来工作。每个这样的事件都包含一个wheelDelta,它等于它要将可滚动区域移动到的px的数量。如果这个值是>0,那么我们向上滚动。如果wheelDelta <0,则向下滚动。

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

@amustill的答案是取消事件,如果<div>的滚动区域已经在顶部或底部的最大位置。但是,当增量大于剩余的可滚动空间时,Internet Explorer将忽略已取消的事件。

换句话说,如果你有一个200px高的<div>包含500px的可滚动内容,而当前的scrollTop是400,一个告诉浏览器再滚动120px的鼠标滚轮事件将导致<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设置为最大值或最小值,这取决于鼠标滚轮事件请求的方向。

由于事件在任何一种情况下都被完全取消,因此它根本不会传播到主体,因此解决了IE以及所有其他浏览器中的问题。

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


使用本地元素滚动属性和mousewheel插件的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();
    }
});

编辑:代码依赖的例子

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


jQuery插件模拟自然滚动的Internet Explorer

  $.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);
                }
            }
        });
    });
};

https://github.com/basselin/jquery-mousewheel-stop-propagation/blob/master/mousewheelStopPropagation.js


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

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

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


我也遇到过类似的情况,我是这样解决的: 所有可滚动的元素使类可滚动。

$(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


作为变量,为了避免滚动或鼠标滚轮处理的性能问题,你可以使用如下代码:

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


如果有人还在寻找一个解决方案,下面的插件做的工作http://mohammadyounes.github.io/jquery-scrollLock/

它完全解决了在给定容器内锁定鼠标滚轮滚动的问题,防止它传播到父元素。

不改变滚轮滚动速度,不会影响用户体验。无论操作系统的鼠标滚轮垂直滚动速度如何,你都可以得到相同的行为(在Windows上,它可以设置为一个屏幕或一行,最多100行每个凹槽)。

演示:http://mohammadyounes.github.io/jquery-scrollLock/example/

来源:https://github.com/MohammadYounes/jquery-scrollLock


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

在这里玩演示。


新的web开发人员在这里。这对我来说在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();
        }
    }
}

不要被行数骗了,其实很简单——只是为了可读性有点啰嗦(自文档代码对吧?)

我还应该提到这里的语言是TypeScript,但和往常一样,将它转换为JS很简单。


上面的方法不是那么自然,经过一些谷歌我找到了一个更好的解决方案,不需要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; // Future browsers element.onmousewheel = wheelHandler; // Most current browsers if (isFirefox) { element.scrollTop = 0; element.addEventListener("DOMMouseScroll", wheelHandler, false); } // prevent from scrolling parrent elements function wheelHandler(event) { var e = event || window.event; // Standard or IE event object // Extract the amount of rotation from the event object, looking // for properties of a wheel event object, a mousewheel event object // (in both its 2D and 1D forms), and the Firefox DOMMouseScroll event. // Scale the deltas so that one "click" toward the screen is 30 pixels. // If future browsers fire both "wheel" and "mousewheel" for the same // event, we'll end up double-counting it here. Hopefully, however, // cancelling the wheel event will prevent generation of mousewheel. var deltaX = e.deltaX * -30 || // wheel event e.wheelDeltaX / 4 || // mousewheel 0; // property not defined var deltaY = e.deltaY * -30 || // wheel event e.wheelDeltaY / 4 || // mousewheel event in Webkit (e.wheelDeltaY === undefined && // if there is no 2D property then e.wheelDelta / 4) || // use the 1D wheel property e.detail * -10 || // Firefox DOMMouseScroll event 0; // property not defined // Most browsers generate one event with delta 120 per mousewheel click. // On Macs, however, the mousewheels seem to be velocity-sensitive and // the delta values are often larger multiples of 120, at // least with the Apple Mouse. Use browser-testing to defeat this. if (isMacWebkit) { deltaX /= 30; deltaY /= 30; } e.currentTarget.scrollTop -= deltaY; // If we ever get a mousewheel or wheel event in (a future version of) // Firefox, then we don't need DOMMouseScroll anymore. if (isFirefox && e.type !== "DOMMouseScroll") { element.removeEventListener("DOMMouseScroll", wheelHandler, false); } // Don't let this event bubble. Prevent any default action. // This stops the browser from using the mousewheel event to scroll // the document. Hopefully calling preventDefault() on a wheel event // will also prevent the generation of a mousewheel event for the // same rotation. if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); e.cancelBubble = true; // IE events e.returnValue = false; // IE events return 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();
                }
            });
        }
    };
})

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();
    }
});

看看Leland Kwong的代码。

基本思路是将wheeleling事件绑定到子元素上,然后使用子元素的原生javascript属性scrollHeight和jquery属性outerHeight来检测滚动的结束,在此基础上返回false以阻止任何滚动。

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;
  }
});

有很多这样的问题,有很多答案,但我找不到一个不涉及事件、脚本、插件等的令人满意的解决方案。我想在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. 模态滚动上没有父滚动

The reason why the ancestor ends up scrolling is because the scroll event bubbles and some element on the chain is able to handle it. A way to stop that is to make sure none of the elements on the chain know how to handle the scroll. In terms of our example, we can refactor the tree to move the modal out of the parent element. For obscure reasons, it is not enough to keep the parent and the modal DOM siblings; the parent must be wrapped by another element that establishes a new stacking context. An absolutely positioned wrapper around the parent can do the trick.

我们得到的结果是,只要模态接收到滚动事件,事件就不会冒泡到“父”元素。

通常应该可以重新设计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.没有滚动的任何地方,除了在模式,而它是

The solution above still allows the parent to receive scroll events, as long as they are not intercepted by the modal window (i.e. if triggered by mousewheel while the cursor is not over the modal). This is sometimes undesirable and we may want to forbid all background scrolling while the modal is up. To do that, we need to insert an extra stacking context that spans the whole viewport behind the modal. We can do that by displaying an absolutely positioned overlay, which can be fully transparent if necessary (but not 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;
}

还有一个有趣的技巧,当鼠标悬停在可滚动元素上时,锁定父元素的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');
});

这是一个简单的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);

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>

希望这能帮助下一个从谷歌搜索到这里的人。


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必须包含可滚动类,而且它都需要在滚动容器类或任何您选择的类中,并且锁定类必须级联。


我从所选的库中绑定了这个: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)

这对我很有用。


在这个线程中给出的所有解决方案都没有提到一个现有的和本地的方法来解决这个问题,而不需要重新排序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行为不再落后于功能标志。


值得一提的是,在像reactJS, AngularJS, VueJS等现代框架中,当处理固定位置元素时,这个问题有简单的解决方案。例如侧板或叠加元素。

这种技术被称为“传送门”,这意味着应用程序中使用的一个组件,不需要从你正在使用它的地方实际提取它,将在body元素的底部装载它的子元素,在你试图避免滚动的父元素之外。

注意,它不会避免滚动body元素本身。你可以结合这种技术,在滚动div中安装你的应用程序,以达到预期的结果。

React material-ui中的门户实现示例:https://material-ui-next.com/api/portal/


有es6跨浏览器+移动香草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)};
}

你可以用CSS来实现这个结果

.isolate-scrolling {
    overscroll-behavior: contain;
}

只有当您的鼠标将子元素留给父元素时,才会滚动父容器。


我们可以简单地使用CSS。 为子滚动容器元素提供一个样式。

 style="overscroll-behavior: contain"

它不会触发父节点的滚动事件。