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

当前回答

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

其他回答

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

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

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

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

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

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

对于那些使用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(非绑定)

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

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