如何暂时禁用滚动?

IT技术 javascript jquery scroll
2021-01-12 21:09:48

我正在使用 scrollTo jQuery 插件,想知道是否可以通过 Javascript 暂时禁用窗口元素上的滚动?我想禁用滚动的原因是,当您在 scrollTo 动画时滚动时,它变得非常难看 ;)

当然,我可以做 a$("body").css("overflow", "hidden");然后在动画停止时将它放回 auto ,但如果滚动条仍然可见但不活动会更好。

6个回答

scroll事件无法取消。但是您可以通过取消这些交互事件来实现:
鼠标 触摸滚动以及与滚动相关的按钮

[工作演示]

// left: 37, up: 38, right: 39, down: 40,
// spacebar: 32, pageup: 33, pagedown: 34, end: 35, home: 36
var keys = {37: 1, 38: 1, 39: 1, 40: 1};

function preventDefault(e) {
  e.preventDefault();
}

function preventDefaultForScrollKeys(e) {
  if (keys[e.keyCode]) {
    preventDefault(e);
    return false;
  }
}

// modern Chrome requires { passive: false } when adding event
var supportsPassive = false;
try {
  window.addEventListener("test", null, Object.defineProperty({}, 'passive', {
    get: function () { supportsPassive = true; } 
  }));
} catch(e) {}

var wheelOpt = supportsPassive ? { passive: false } : false;
var wheelEvent = 'onwheel' in document.createElement('div') ? 'wheel' : 'mousewheel';

// call this to Disable
function disableScroll() {
  window.addEventListener('DOMMouseScroll', preventDefault, false); // older FF
  window.addEventListener(wheelEvent, preventDefault, wheelOpt); // modern desktop
  window.addEventListener('touchmove', preventDefault, wheelOpt); // mobile
  window.addEventListener('keydown', preventDefaultForScrollKeys, false);
}

// call this to Enable
function enableScroll() {
  window.removeEventListener('DOMMouseScroll', preventDefault, false);
  window.removeEventListener(wheelEvent, preventDefault, wheelOpt); 
  window.removeEventListener('touchmove', preventDefault, wheelOpt);
  window.removeEventListener('keydown', preventDefaultForScrollKeys, false);
}

更新:修复了带有被动侦听器的 Chrome 桌面和现代移动浏览器

滚动条没有被禁用。
2021-03-13 21:09:48
给陷入此陷阱的其他开发人员的提示:请确保从其他 jQuery 尝试中删除所有 'e.stopPropagation()' 调用以停止滚动,因为它不仅不起作用,而且防止事件冒泡到此代码那确实有效。希望我浪费的 30 分钟将有助于节省其他人的时间:)
2021-03-14 21:09:48
我可以像往常一样滚动它:使用中键按下并移动鼠标......因此这个技巧不会影响像我这样的用户;)
2021-03-14 21:09:48
您可以将 32(空格)添加到禁用的键数组(在代码注释中显示)。
2021-03-26 21:09:48
我仍然可以通过在页面的顶部/底部拖动文件来使其滚动。这也可以通过选择页面上的文本并在顶部/底部进行相同的拖动来实现。
2021-03-28 21:09:48

只需向主体添加一个类即可:

.stop-scrolling {
  height: 100%;
  overflow: hidden;
}

添加该类,然后在您想要重新启用滚动时删除,在 IE、FF、Safari 和 Chrome 中进行了测试。

$('body').addClass('stop-scrolling')

对于移动设备,您需要处理touchmove事件:

$('body').bind('touchmove', function(e){e.preventDefault()})

并取消绑定以重新启用滚动。在 iOS6 和 Android 2.3.3 中测试

$('body').unbind('touchmove')
此解决方案有效,但当您将此类应用于正文时(例如),滚动条会消失并创建“凹凸”效果(在窗口操作系统下)
2021-03-12 21:09:48
虽然此解决方案确实有效,但它具有(可能)不受欢迎的滚动回页面顶部的效果。
2021-03-18 21:09:48
知道了!您必须处理该touchmove事件,就像$('body').bind('touchmove', function(e){e.preventDefault()}). 编辑此答案以包含此移动解决方案。
2021-03-25 21:09:48
很酷,只需要确保任何内部滚动都可以在触摸设备的模态中工作。可以在模态下方进行叠加并防止叠加层而不是主体上的默认触摸移动。
2021-03-27 21:09:48
这对我不起作用,除非我的选择器是 $('body,html')
2021-04-04 21:09:48

这是一个非常基本的方法:

window.onscroll = function () { window.scrollTo(0, 0); };

它在 IE6 中有点跳跃。

即使它并没有真正禁用它,它也会模拟它,这对我来说已经足够了。
2021-03-09 21:09:48
恕我直言 - 最好的答案在这里。另外,您不必将其锁定到(0, 0),只需使用当前滚动位置即可。
2021-03-09 21:09:48
@Marcus 与不可取消的事件一样好。
2021-03-17 21:09:48
但是我们如何重新启用它呢?
2021-03-18 21:09:48
并不是真正的禁用,更像是尝试滚动时的默认设置。
2021-04-03 21:09:48

以下解决方案是基本但纯 JavaScript(无 jQuery):

function disableScrolling(){
    var x=window.scrollX;
    var y=window.scrollY;
    window.onscroll=function(){window.scrollTo(x, y);};
}

function enableScrolling(){
    window.onscroll=function(){};
}
在 Safari 7.1 和 IE 11 中跳跃。最新的 Chrome、Firefox、Opera 没问题。
2021-03-11 21:09:48
你可以设置window.onscroll=null而不是添加一个空的匿名函数,null是初始值window.onload
2021-03-14 21:09:48
在最新的 Chrome 上仍然有点紧张
2021-04-01 21:09:48
工作正常,在 safari、chrome 中,但在 IE 中闪烁
2021-04-06 21:09:48
如果此解决方案不适用于某些浏览器,那就是浏览器问题
2021-04-08 21:09:48

此解决方案将在禁用滚动时保持当前滚动位置,这与将用户跳回顶部的某些解决方案不同。

它基于galambalazs 的答案,但支持触摸设备,并使用 jquery 插件包装器重构为单个对象。

演示在这里。

在 github 上。

/**
 * $.disablescroll
 * Author: Josh Harrison - aloof.co
 *
 * Disables scroll events from mousewheels, touchmoves and keypresses.
 * Use while jQuery is animating the scroll position for a guaranteed super-smooth ride!
 */

;(function($) {

    "use strict";

    var instance, proto;

    function UserScrollDisabler($container, options) {
        // spacebar: 32, pageup: 33, pagedown: 34, end: 35, home: 36
        // left: 37, up: 38, right: 39, down: 40
        this.opts = $.extend({
            handleKeys : true,
            scrollEventKeys : [32, 33, 34, 35, 36, 37, 38, 39, 40]
        }, options);

        this.$container = $container;
        this.$document = $(document);
        this.lockToScrollPos = [0, 0];

        this.disable();
    }

    proto = UserScrollDisabler.prototype;

    proto.disable = function() {
        var t = this;

        t.lockToScrollPos = [
            t.$container.scrollLeft(),
            t.$container.scrollTop()
        ];

        t.$container.on(
            "mousewheel.disablescroll DOMMouseScroll.disablescroll touchmove.disablescroll",
            t._handleWheel
        );

        t.$container.on("scroll.disablescroll", function() {
            t._handleScrollbar.call(t);
        });

        if(t.opts.handleKeys) {
            t.$document.on("keydown.disablescroll", function(event) {
                t._handleKeydown.call(t, event);
            });
        }
    };

    proto.undo = function() {
        var t = this;
        t.$container.off(".disablescroll");
        if(t.opts.handleKeys) {
            t.$document.off(".disablescroll");
        }
    };

    proto._handleWheel = function(event) {
        event.preventDefault();
    };

    proto._handleScrollbar = function() {
        this.$container.scrollLeft(this.lockToScrollPos[0]);
        this.$container.scrollTop(this.lockToScrollPos[1]);
    };

    proto._handleKeydown = function(event) {
        for (var i = 0; i < this.opts.scrollEventKeys.length; i++) {
            if (event.keyCode === this.opts.scrollEventKeys[i]) {
                event.preventDefault();
                return;
            }
        }
    };


    // Plugin wrapper for object
    $.fn.disablescroll = function(method) {

        // If calling for the first time, instantiate the object and save
        // reference. The plugin can therefore only be instantiated once per
        // page. You can pass options object in through the method parameter.
        if( ! instance && (typeof method === "object" || ! method)) {
            instance = new UserScrollDisabler(this, method);
        }

        // Instance already created, and a method is being explicitly called,
        // e.g. .disablescroll('undo');
        else if(instance && instance[method]) {
            instance[method].call(instance);
        }

    };

    // Global access
    window.UserScrollDisabler = UserScrollDisabler;

})(jQuery);
如果禁用滚动按钮确实有效,可能会有所帮助
2021-03-22 21:09:48
请无视,我发现绑定它很有mousewheel魅力
2021-03-24 21:09:48
在 Chrome(38、Windows 7)上,我仍然可以通过单击并按住中间按钮然后拖动来滚动。
2021-03-26 21:09:48
很高兴它有用。NB 我已经用jQuery 插件格式链接进行了编辑
2021-03-28 21:09:48
@ user1672694,它在 Chrome 中工作。你的浏览器是什么,你在哪个演示页面上发现了这个错误?控制台中的任何 JS 错误?
2021-04-06 21:09:48