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

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


当前回答

Galambalazs的解决方案很棒!它在Chrome和Firefox中都非常适合我。它还可以扩展,以防止来自浏览器窗口的任何默认事件。 假设你在画布上做一个应用。你可以这样做:

var events = {
  preventDefault: function(e) {
    e = e || window.event;
    if (e.preventDefault) e.preventDefault();
    e.returnValue = false;  
  },

  //spacebar: 32, pageup: 33, pagedown: 34, end: 35, home: 36,
  //left: 37, up: 38, right: 39, down: 40
  keys: [32, 33, 34, 35, 36, 37, 38, 39, 40],
  keydown: function(e) {
    for (var i = events.keys.length; i--;) {
      if (e.keyCode === events.keys[i]) {
        events.preventDefault(e);
        return;
      }
    }
  },

  wheel: function(e) {
    events.preventDefault(e);
  },

  disable: function() {
    if (window.addEventListener) {
      window.addEventListener('DOMMouseScroll', events.wheel, false);
    }
    window.onmousewheel = document.onmousewheel = events.wheel;
    document.onkeydown = helpers.events.keydown;
  },

  enable: function() {
    if (window.removeEventListener) {
      window.removeEventListener('DOMMouseScroll', events.wheel, false);
    }
    window.onmousewheel = document.onmousewheel = document.onkeydown = null;  
  }
}

然后在你的应用程序中,假设你要处理你自己的事件,比如鼠标、键盘、触摸事件等等。你可以在鼠标进入画布时禁用默认事件,并在鼠标离开时重新启用它们:

function setMouseEvents(canvas) {
  var useCapture = false;

  //Mouse enter event
  canvas.addEventListener('mouseenter', function(event) {
    events.disable();
  }, useCapture);

  //Mouse leave event
  canvas.addEventListener('mouseleave', function(event) {
    events.enable();
  }, useCapture);
}

你甚至可以禁用右键菜单与此hack:

function disableRightClickMenu(canvas) {
  var my_gradient = canvas.context.createLinearGradient(0, 0, 0, 225);
  my_gradient.addColorStop(0, "white");
  my_gradient.addColorStop(1, "white");
  canvas.context.fillStyle = my_gradient;
  canvas.context.fillRect(0, 0, canvas.width, canvas.height);
  canvas.oncontextmenu = function() { return false; };
}

其他回答

这个解决方案将保持当前的滚动位置,而滚动是禁用的,不像有些跳回用户顶部。

它是基于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);
var winX = null;
var winY = null;

window.addEventListener('scroll', function () {
    if (winX !== null && winY !== null) {
        window.scrollTo(winX, winY);
    }
});

function disableWindowScroll() {
    winX = window.scrollX;
    winY = window.scrollY;
}

function enableWindowScroll() {
    winX = null;
    winY = null;
}

这个怎么样?(如果你正在使用jQuery)

var $window = $(window);
var $body = $(window.document.body);

window.onscroll = function() {
    var overlay = $body.children(".ui-widget-overlay").first();

    // Check if the overlay is visible and restore the previous scroll state
    if (overlay.is(":visible")) {
        var scrollPos = $body.data("scroll-pos") || { x: 0, y: 0 };
        window.scrollTo(scrollPos.x, scrollPos.y);
    }
    else {
        // Just store the scroll state
        $body.data("scroll-pos", { x: $window.scrollLeft(), y: $window.scrollTop() });
    }
};

不,我不会使用事件处理,因为:

不是所有的事件都能保证到达身体, 选择文本并向下移动实际上是在滚动文档, 如果在分离某事物的阶段出了差错,你就完蛋了。

我已经咬了这个通过制作一个隐藏的文本区域复制粘贴动作,猜什么,页面滚动每当我做复制,因为内部我必须在我调用document.execCommand('copy')之前选择文本区域。

不管怎样,这就是我的方式,注意setTimeout():

document.body.setAttribute('style','overflow:hidden;');
// do your thing...
setTimeout(function(){document.body.setAttribute('style','overflow:visible;');}, 500);

当滚动条暂时消失时,会出现动量闪烁,但这是可以接受的。

我在移动屏幕上有类似的动画问题,但在笔记本电脑上没有,当尝试使用jquery的animate命令动画一个div时。所以我决定使用一个计时器来频繁地恢复窗口的滚动位置,这样肉眼就能看到文档是静态的。这一解决方案在三星Galaxy-2或iphone-5等小屏幕移动设备上运行良好。

该方法的主要逻辑:设置窗口滚动位置到原始滚动位置的定时器应该在jquery animate命令之前启动,然后当动画完成时,我们需要清除这个定时器(原始滚动位置是动画开始之前的位置)。

我惊喜地发现,如果计时器间隔为1毫秒,文档在动画持续时间内实际上是静态的,这正是我的目标。

//get window scroll position prior to animation
//so we can keep this position during animation
var xPosition = window.scrollX || window.pageXOffset || document.body.scrollLeft;
var yPosition = window.scrollY || window.pageYOffset || document.body.scrollTop;

//NOTE:restoreTimer needs to be global variable
//start the restore timer
restoreTimer = setInterval(function() {
    window.scrollTo(xPosition, yPosition);
}, 1);

//animate the element emt
emt.animate({
    left: "toggle",
    top: "toggle",
    width: "toggle",
    height: "toggle"
}, 500, function() {
    //when animation completes, we stop the timer
    clearInterval(restoreTimer);
});

另一个有效的解决方案:根据Mohammad Anini在这篇文章中关于启用/禁用滚动的回答,我还发现修改后的代码版本如下所示有效。

//get current scroll position
var xPosition = window.scrollX || window.pageXOffset || document.body.scrollLeft;
var yPosition = window.scrollY || window.pageYOffset || document.body.scrollTop;

//disable scrolling
window.onscroll = function() {
    window.scrollTo(xPosition, yPosition);
};

//animate and enable scrolling when animation is completed
emt.animate({
    left: "toggle",
    top: "toggle",
    width: "toggle",
    height: "toggle"
}, 500, function() {
    //enable scrolling when animation is done
    window.onscroll = function() {};
});