Как временно отключить прокрутку?

435

Я использую плагин scrollTo jQuery и хотел бы узнать, возможно ли как-то временно отключить прокрутку элемента окна через Javascript? Причина, по которой я хотел бы отключить прокрутку, состоит в том, что когда вы прокручиваете, когда scrollTo анимирует, это становится действительно уродливым;)

Конечно, я мог бы сделать $("body").css("overflow", "hidden");и затем вернуть его в автоматический режим, когда анимация остановится, но было бы лучше, если бы полоса прокрутки была все еще видимой, но неактивной.

Оливье Лалонд
источник
12
Если это все еще показывает, то пользователь обучен думать, что это должно функционировать. Если доза не перемещается или доза не реагирует, это нарушит ментальную модель работы пользователя и приведет к путанице. Я бы просто нашел лучший способ справиться с прокруткой во время анимации, например, остановить анимацию.
Маркус Уайброу
Другое решение: stackoverflow.com/questions/9280258/…
gdbj

Ответы:

731

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 и современные мобильные браузеры с пассивными слушателями

gblazex
источник
114
Совет для других разработчиков, застрявших в этой ловушке: убедитесь, что вы удаляете все вызовы e.stopPropagation () из других jQuery, пытаясь остановить прокрутку, потому что это не только не работает, но и предотвращает всплытие события в ЭТОТ код. это работает. Надеюсь, мои потраченные 30 минут помогут сэкономить чужое время :)
Дирк ван Берген
4
Вы можете добавить 32 (пробел) в массив отключенных ключей (показать в комментариях к коду).
gblazex
14
Я могу прокручивать это, как всегда: используя нажатие средней кнопки и перемещая мышь ... Поэтому этот трюк не повлияет на таких пользователей, как я;)
Денис V
11
Полоса прокрутки не отключена.
Веризм
8
Это больше не работает на Chrome
PerrierCitror
428

Сделайте это, просто добавив класс к телу:

.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')
hallodom
источник
4
Понял! Вы должны обработать touchmoveсобытие, как с $('body').bind('touchmove', function(e){e.preventDefault()}). Отредактировал этот ответ, чтобы включить это мобильное решение.
MusikAnimal
3
Круто, просто нужно убедиться, что любая внутренняя прокрутка может работать в модальном для сенсорного устройства. Может сделать наложение только под модальным и предотвратить перемещение по умолчанию на оверлей вместо тела.
Привет
63
Хотя это решение действительно работает, оно имеет (потенциально) нежелательный эффект прокрутки назад к верхней части страницы.
Мэтт
3
Это не сработало для меня, если мой селектор не был$('body,html')
PickYourPoison
22
Это решение работает, но полоса прокрутки исчезает и создает эффект «поднять» (под окном окна), когда вы применяете этот класс к телу (например)
Georgio
57

Вот действительно простой способ сделать это:

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

Это немного нервно в IE6.

sdleihssirhc
источник
14
На самом деле это не отключение, больше похоже на привязку к значению по умолчанию при попытке прокрутки.
Маркус Уайброу
11
@ Маркус Так же хорошо, как это получится с событием, которое нельзя отменить.
sdleihssirhc
3
Несмотря на то, что он не отключает его по-настоящему, он имитирует это, и для меня этого достаточно.
Крис Бьер
11
ИМХО - лучший ответ здесь. Кроме того, вам не нужно блокировать его (0, 0), просто используйте текущую позицию прокрутки.
YemSalat
4
Но как мы можем включить это?
Кибернетический
41

Следующее решение является базовым, но чистым JavaScript (без jQuery):

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

function enableScrolling(){
    window.onscroll=function(){};
}
Мухаммед Анини
источник
3
Jumpy в Safari 7.1 и IE 11. Новейший Chrome, Firefox, Opera ok.
Тимо Кяхконен
Все еще немного нервный на новейшем Chrome
Джейсон Оллсхорн
Работает нормально, в сафари, хром, но мерцает в IE
Bhuvan Arora
Если это решение не работает для какого-либо браузера, то это проблема браузеров
Ото Шавадзе
Как уже упоминалось в другом ответе, scroll-behavior: smoothBorks это. Кроме того, я не согласен с Ото, который говорит, что это вина браузера. Вы в основном предполагаете, что что-то произойдет мгновенно, когда на самом деле это асинхронно
Мэтт Флетчер
25

Это решение будет поддерживать текущую позицию прокрутки, пока прокрутка отключена, в отличие от некоторых, которые возвращают пользователя наверх.

Он основан на ответе галамбалаза , но с поддержкой сенсорных устройств и рефакторинг как единый объект с оболочкой плагина 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);
Джош Харрисон
источник
Рад, что это полезно. NB Я редактировал со ссылкой на это в формате плагина jQuery .
Джош Харрисон
Может помочь, если кнопка отключения прокрутки действительно сработала
cameronjonesweb
@ user1672694, здесь работает в Chrome. Какой у вас браузер и на какой демо-странице вы обнаружили ошибку? Любые ошибки JS в консоли?
Джош Харрисон
В Chrome (38, Windows 7) я все еще могу прокручивать, нажимая и удерживая среднюю кнопку, а затем перетаскивая.
Сетхи
1
Пожалуйста, не mousewheel
обращайте
17

Мне жаль отвечать на старый пост, но я искал решение и наткнулся на этот вопрос.

Существует много способов решения этой проблемы, чтобы по-прежнему отображать полосу прокрутки, например, придание контейнеру 100% высоты и overflow-y: scrollстиля.

В моем случае я только что создал div с полосой прокрутки, которую я отображаю при добавлении overflow: hiddenв тело:

function disableScroll() {
    document.getElementById('scrollbar').style.display = 'block';
    document.body.style.overflow = 'hidden';
}

Панель прокрутки элемента должна иметь следующие стили:

overflow-y: scroll; top: 0; right: 0; display: none; height: 100%; position: fixed;

Это показывает серую полосу прокрутки, надеюсь, это поможет будущим посетителям.

lisovaccaro
источник
8

Я искал решение этой проблемы, но не был удовлетворен каким-либо из вышеперечисленных решений ( на момент написания этого ответа ), поэтому я придумал это решение ..

CSS

.scrollDisabled {   
    position: fixed;
    margin-top: 0;// override by JS to use acc to curr $(window).scrollTop()
    width: 100%;
}

JS

var y_offsetWhenScrollDisabled=0;

function disableScrollOnBody(){
    y_offsetWhenScrollDisabled= $(window).scrollTop();
    $('body').addClass('scrollDisabled').css('margin-top', -y_offsetWhenScrollDisabled);
}
function enableScrollOnBody(){
    $('body').removeClass('scrollDisabled').css('margin-top', 0);
    $(window).scrollTop(y_offsetWhenScrollDisabled);
}
Раджат Гупта
источник
Я обнаружил, что это работает для меня, если я добавлю overflow-y: scrollк .scrollDisabledстилю. В противном случае произошел небольшой скачок, поскольку полоса прокрутки каждый раз пряталась. Конечно, это работает только для меня, потому что моя страница достаточно длинная, чтобы иметь полосу прокрутки даже на самых больших экранах.
Эндрю Майнер
7

В соответствии с постом galambalazs я бы добавил поддержку сенсорных устройств, позволяющую нам касаться, но не прокручивать вверх или вниз:

function disable_scroll() {
   ...
   document.ontouchmove = function(e){ 
        e.preventDefault(); 
   }
}

function enable_scroll() {
   ...
   document.ontouchmove = function(e){ 
     return true; 
   }
}
jvalen
источник
3
Вы уверены, что это ответ, а не просто комментарий другого ответа?
IvanH
6

Начиная с Chrome 56 и других современных браузеров, вы должны добавить passive:falseк addEventListenerвызову, чтобы сделать preventDefaultработу. Поэтому я использую это, чтобы остановить прокрутку на мобильном телефоне:

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

function disableScroll(){
    document.body.addEventListener('touchmove', preventDefault, { passive: false });
}
function enableScroll(){
    document.body.removeEventListener('touchmove', preventDefault, { passive: false });
}
Hokascha
источник
5

Нет, я бы не стал заниматься обработкой событий, потому что:

  • не все события гарантированно достигают тела,

  • выделение текста и перемещение вниз фактически прокручивает документ,

  • если на этапе события отсоединение что-то пошло не так, вы обречены.

Я укусил это, выполнив действие копирования-вставки со скрытой текстовой областью, и угадайте, что прокручивает страницу всякий раз, когда я делаю копию, потому что внутренне я должен выбрать текстовую область перед вызовом document.execCommand('copy').

Во всяком случае, так я иду, обратите внимание setTimeout():

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

Мигает импульс, поскольку полосы прокрутки на мгновение исчезают, но это приемлемо.

Centurian
источник
4

В зависимости от того, чего вы хотите добиться с помощью удаленной прокрутки, вы можете просто зафиксировать элемент, из которого вы хотите удалить прокрутку (по щелчку или любой другой триггер, который вы хотите временно отключить прокрутку).

Я искал решение для временного отсутствия прокрутки и для моих нужд, это решило его

сделать класс

.fixed{
    position: fixed;
}

затем с Jquery

var someTrigger = $('#trigger'); //a trigger button
var contentContainer = $('#content'); //element I want to temporarily remove scroll from

contentContainer.addClass('notfixed'); //make sure that the element has the "notfixed" class

//Something to trigger the fixed positioning. In this case we chose a button.
someTrigger.on('click', function(){

    if(contentContainer.hasClass('notfixed')){
        contentContainer.removeClass('notfixed').addClass('fixed');

    }else if(contentContainer.hasClass('fixed')){
        contentContainer.removeClass('fixed').addClass('notfixed');
    };
});

Я обнаружил, что это достаточно простое решение, которое хорошо работает во всех браузерах, а также подходит для простого использования на портативных устройствах (например, iPhone, планшетах и ​​т. Д.). Поскольку элемент временно исправлен, прокрутки нет :)

НОТА! В зависимости от размещения вашего элемента «contentContainer» вам может потребоваться настроить его слева. Что можно легко сделать, добавив левое значение CSS к этому элементу, когда активен фиксированный класс

contentContainer.css({
    'left': $(window).width() - contentContainer.width()/2 //This would result in a value that is the windows entire width minus the element we want to "center" divided by two (since it's only pushed from one side)
});
axelra82
источник
4

Другое решение:

body {
    overflow-y: scroll;
    width: 100%;
    margin: 0 auto;
}

Таким образом, у вас всегда есть вертикальная полоса прокрутки, но, поскольку большая часть моего контента длиннее, чем область просмотра, это нормально для меня. Контент центрируется отдельным div, но без повторного задания поля в теле мой контент остался бы слева.

Вот две функции, которые я использую, чтобы показать мой всплывающий / модальный:

var popup_bodyTop = 0;
var popup_bodyLeft = 0;

function popupShow(id)
{
    $('#'+ id).effect('fade');
    $('#popup-overlay').effect('fade');

    // remember current scroll-position
    // because when setting/unsetting position: fixed to body
    // the body would scroll to 0,0
    popup_bodyLeft = $(document).scrollLeft();
    popup_bodyTop  = $(document).scrollTop();

    // invert position
    var x = - popup_bodyLeft;
    var y = - popup_bodyTop;

    $('body').css('position', 'fixed');
    $('body').css('top', y.toString() +'px');
    $('body').css('left', x.toString() +'px');
}

function popupHide(id)
{
    $('#'+ id).effect('fade');
    $('#popup-overlay').effect('fade');
    $('body').css('position', '');
    $('html, body').scrollTop(popup_bodyTop);
    $('html, body').scrollLeft(popup_bodyLeft);
}

Результат: не прокручиваемый фон и отсутствие перемещения контента из-за левой полосы прокрутки. Протестировано с текущими FF, Chrome и IE 10.

Marco
источник
Это работало для меня, и проблема прокрутки к вершине после использования позиции: исправлена. Спасибо!
Анния Мартинес
3

Как насчет этого? (Если вы используете 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() });
    }
};
Дэн
источник
немного нервный, но это работает для IE 7 (клиент использует его). других решений нет.
Ники б
3

Я использую showModalDialog , для отображения вторичной страницы в качестве модального диалога.

чтобы скрыть полосы прокрутки главного окна:

document.body.style.overflow = "hidden";

и при закрытии модального диалога, показывая полосы прокрутки главного окна:

document.body.style.overflow = "scroll";

чтобы получить доступ к элементам в главном окне из диалога:

parent.document.getElementById('dialog-close').click();

просто для тех, кто ищет showModalDialog : (после строки 29 исходного кода)

document.getElementById('dialog-body').contentWindow.dialogArguments = arg;
document.body.style.overflow = "hidden";//****
document.getElementById('dialog-close').addEventListener('click', function(e) {
    e.preventDefault();
    document.body.style.overflow = "scroll";//****
    dialog.close();
});
Zolfaghari
источник
Это сработало для меня в React, где jQuery не существует и где React не имеет доступа для управления состоянием тега body.
Джон
3

Отмена события, как в принятом ответе, на мой взгляд, ужасный метод: /

Вместо этого я использовал position: fixed; top: -scrollTop();ниже.

Демо: https://jsfiddle.net/w9w9hthy/5/

Из моего всплывающего проекта jQuery: https://github.com/seahorsepip/jPopup

//Freeze page content scrolling
function freeze() {
    if($("html").css("position") != "fixed") {
        var top = $("html").scrollTop() ? $("html").scrollTop() : $("body").scrollTop();
        if(window.innerWidth > $("html").width()) {
            $("html").css("overflow-y", "scroll");
        }
        $("html").css({"width": "100%", "height": "100%", "position": "fixed", "top": -top});
    }
}

//Unfreeze page content scrolling
function unfreeze() {
    if($("html").css("position") == "fixed") {
        $("html").css("position", "static");
        $("html, body").scrollTop(-parseInt($("html").css("top")));
        $("html").css({"position": "", "width": "", "height": "", "top": "", "overflow-y": ""});
    }
}

Этот код учитывает проблемы ширины, высоты, полосы прокрутки и скачка страницы.

Возможные проблемы, решенные с помощью приведенного выше кода:

  • ширина, при фиксированной позиции установки ширина элемента HTML может быть меньше 100%
  • высота такая же, как выше
  • полоса прокрутки, при фиксированной настройке положения содержимое страницы больше не имеет полосы прокрутки, даже если она имела полосу прокрутки, прежде чем возник горизонтальный скачок страницы
  • pagejump, когда установка положения фиксирована, scrollTop больше не действует, что приводит к вертикальному скачку страницы

Если у кого-то есть какие-либо улучшения в коде замораживания / размораживания вышеупомянутой страницы, дайте мне знать, чтобы я мог добавить эти улучшения в свой проект.

seahorsepip
источник
3
var winX = null, 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;
};
Văn Quyết
источник
1
Это лучшее решение здесь.
Jfunk
@jfunk согласен, просто и лаконично, маленький код, идеально. Спасибо
Флоран Рок
2

У меня та же проблема, ниже, как я справлюсь с этим.

/* file.js */
var body = document.getElementsByTagName('body')[0];
//if window dont scroll
body.classList.add("no-scroll");
//if window scroll
body.classList.remove("no-scroll");

/* file.css */
.no-scroll{
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

надеюсь, это поможет.

Роберт
источник
1

Основываясь на ответе Шайенн Форбс, который я нашел здесь через fcalderan: просто отключить прокрутку, а не скрыть ее? и исправить проблему Hallodom исчезнувшей полосы прокрутки

CSS:

.preventscroll{
    position: fixed;
    overflow-y:scroll;
}

JS:

whatever.onclick = function(){
    $('body').addClass('preventscroll');
}
whatevertoclose.onclick = function(){
    $('body').removeClass('preventscroll');
}

Этот код поднимает вас наверх страницы, но я думаю, что код fcalderan имеет обходной путь.

каламбур
источник
1

Я знаю, что это старый вопрос, но я должен был сделать что-то очень похожее, и через некоторое время, пытаясь найти ответ и испробовав разные подходы, я решил использовать очень простое решение.

Моя проблема была очень похожа, почти идентична, с той лишь разницей, что мне не нужно было показывать полосу прокрутки - я просто должен был убедиться, что ее ширина будет по-прежнему использоваться, чтобы ширина страницы не изменялась, пока отображалось мое наложение ,

Когда я начинаю вставлять наложение в экран, я делаю:

$('body').addClass('stop-scrolling').css('margin-right', 8);

и после того, как я сдвигаю свое наложение с экрана, я делаю:

$('body').removeClass('stop-scrolling').css('margin-right', 0);

ВАЖНО: это работает отлично, потому что мой оверлей позиционируется absolute, right: 0pxкогда visible.

user2430829
источник
1

Самый простой метод:

$("body").css("overflow", "hidden"); // Remove the scroll bar temporarily

Чтобы отменить это:

$("body").css("overflow", "auto");

Легко реализовать, но единственным недостатком является:

  • Страница немного переместится влево, если она выровнена по центру (по горизонтали).

Это связано с удалением полосы прокрутки и увеличением области просмотра.

Даан
источник
1
это сбросит позицию прокрутки
Angel David Calderaro Pacciott
@AngelDavidCalderaroPacciott Нет, позиция прокрутки останется прежней высоты / расстояния.
Даан
@ Даан сбрасывает позицию прокрутки в Chrome
Том
@ Я только что проверил это, он делает это только в некоторых случаях (когда рост не по отношению к своим детям). Пожалуйста , попробуйте изменить , bodyчтобы htmlвместо этого.
Даан
Могу поспорить, что вы не проверяли свое решение в Iphone, потому overflow:hiddenчто там не работает
Шуво
1

Вот мое решение, чтобы остановить прокрутку (без jQuery). Я использую его для отключения прокрутки, когда появляется боковое меню.

<button onClick="noscroll()" style="position:fixed; padding: 8px 16px;">Disable/Enable scroll</button>
<script>
var noscroll_var;
function noscroll(){
  if(noscroll_var){
    document.getElementsByTagName("html")[0].style.overflowY = "";
    document.body.style.paddingRight = "0";
    noscroll_var = false
  }else{
    document.getElementsByTagName("html")[0].setAttribute('style', 'overflow-y: hidden !important');
    document.body.style.paddingRight = "17px";
    noscroll_var = true
  }
}/*noscroll()*/
</script>

<!-- Just to fill the page -->
<script>
  for(var i=0; i <= 80; i++){
    document.write(i + "<hr>")
  }
</script>

Я добавил 17px отступа вправо, чтобы компенсировать исчезновение полосы прокрутки. Но это также проблематично, в основном для мобильных браузеров. Решается путем получения ширины стержня в соответствии с этим .

Все вместе в этой ручке.

Josep81
источник
1

Это самое простое решение, которое я получил до сих пор. И поверьте мне, я попробовал все остальные, и это самый простой. Он отлично работает на устройствах с Windows , где страница сдвигается вправо, чтобы освободить место для системной полосы прокрутки и устройств IOS, которым не требуется место для их полос прокрутки в браузерах. Таким образом, при использовании этого вам не нужно добавлять отступ справа, чтобы страница не мерцала, когда вы скрываете переполнение тела или HTML с помощью CSS .

Решение довольно простое, если подумать. Идея состоит в том, чтобы дать window.scrollTop () ту же самую точную позицию в момент открытия всплывающего окна. Также измените эту позицию, когда размер окна изменится (так как позиция прокрутки изменяется, когда это происходит).

Итак, поехали ...

Сначала давайте создадим переменную, которая сообщит вам, что всплывающее окно открыто, и назовем его stopWindowScroll . Если мы этого не сделаем, вы получите ошибку неопределенной переменной на своей странице и установите ее в 0 - как неактивная.

$(document).ready(function(){
    stopWindowScroll = 0;
});

Теперь давайте сделаем так, чтобы функция open popup могла быть любой функцией в вашем коде, которая запускает любое всплывающее окно, которое вы используете как плагин или пользовательский. В этом случае это будет простое настраиваемое всплывающее окно с простой функцией щелчка документа.

$(document).on('click','.open-popup', function(){
    // Saving the scroll position once opening the popup.
    stopWindowScrollPosition = $(window).scrollTop();
    // Setting the stopWindowScroll to 1 to know the popup is open.
    stopWindowScroll = 1;
    // Displaying your popup.
    $('.your-popup').fadeIn(300);
});

Итак, следующее, что мы делаем, это создаем функцию закрытия всплывающих окон, которая, повторяю, может быть любой функцией, которую вы уже создали или используете в плагине. Важно то, что нам нужны эти две функции, чтобы установить переменную stopWindowScroll в 1 или 0, чтобы знать, когда она открыта или закрыта.

$(document).on('click','.open-popup', function(){
    // Setting the stopWindowScroll to 0 to know the popup is closed.
    stopWindowScroll = 0;
    // Hiding your popup
    $('.your-popup').fadeOut(300);
});

Затем давайте создадим функцию window.scroll, чтобы мы могли предотвратить прокрутку, как только упомянутый выше stopWindowScroll установлен в 1 - как активный.

$(window).scroll(function(){
    if(stopWindowScroll == 1) {
         // Giving the window scrollTop() function the position on which
         // the popup was opened, this way it will stay in its place.
         $(window).scrollTop(stopWindowScrollPosition);
    }
});

Это оно. Для этого не требуется CSS, кроме ваших собственных стилей для страницы. Для меня это сработало, и я надеюсь, что это поможет вам и другим.

Вот рабочий пример на JSFiddle:

Пример JS Fiddle

Дайте мне знать, если это помогло. С уважением.

Архитектор
источник
1

Сохраняйте длину прокрутки в глобальной переменной и восстанавливайте ее при необходимости!

var sctollTop_length = 0;

function scroll_pause(){
  sctollTop_length = $(window).scrollTop();
  $("body").css("overflow", "hidden");
}

function scroll_resume(){
  $("body").css("overflow", "auto");
  $(window).scrollTop(sctollTop_length);
}
Карима
источник
1

Этот код будет работать на Chrome 56 и далее (оригинальный ответ больше не работает на Chrome).

Используйте DomUtils.enableScroll()для включения прокрутки.

Используйте DomUtils.disableScroll()для отключения прокрутки.

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

  static preventDefault(e) {
    e = e || window.event;
    if (e.preventDefault) e.preventDefault();
    e.returnValue = false;
  }

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

  static disableScroll() {
    document.addEventListener('wheel', DomUtils.preventDefault, {
      passive: false,
    }); // Disable scrolling in Chrome
    document.addEventListener('keydown', DomUtils.preventDefaultForScrollKeys, {
      passive: false,
    });
  }

  static enableScroll() {
    document.removeEventListener('wheel', DomUtils.preventDefault, {
      passive: false,
    }); // Enable scrolling in Chrome
    document.removeEventListener(
      'keydown',
      DomUtils.preventDefaultForScrollKeys,
      {
        passive: false,
      }
    ); // Enable scrolling in Chrome
  }
}
PerrierCitror
источник
1

Чтобы предотвратить прыжок, это то, что я использовал

export function toggleBodyScroll(disable) {
  if (!window.tempScrollTop) {
    window.tempScrollTop = window.pageYOffset; 
    // save the current position in a global variable so I can access again later

  }
  if (disable) {
    document.body.classList.add('disable-scroll');
    document.body.style.top = `-${window.tempScrollTop}px`;
  } else {
    document.body.classList.remove('disable-scroll');
    document.body.style.top = `0px`;
    window.scrollTo({top: window.tempScrollTop});
    window.tempScrollTop = 0;
  }
}

и в моем css

.disable-scroll {
  height: 100%;
  overflow: hidden;
  width: 100%;
  position: fixed;
}
Milad
источник
0

Я нашел этот ответ на другом сайте :

Отключить прокрутку:

$( ".popup").live({
    popupbeforeposition: function(event, ui) {
    $("body").on("touchmove", false);
}
});

После закрытия всплывающего окна прокрутки:

$( ".popup" ).live({
    popupafterclose: function(event, ui) {
    $("body").unbind("touchmove");
}
});
pennstump
источник
Кажется, что это останавливает прокрутку касанием, но прокрутка мышью, клавиши со стрелками, клавиши перемещения вверх и вниз и т.д. будут работать. -1
markasoftware
Эти «события» предназначены для сенсорной прокрутки, просто замените любые события, которые вам нужны.
Пеннштамп
1
также, это, кажется, используется в некоторой другой очень специфической ситуации. popupbeforeposition? Для чего это нужно? Какое это имеет отношение к временному отключению прокрутки? По крайней мере, сделайте это соответствующим этой ситуации. Похоже, вы скопировали это прямо с сайта.
markasoftware
0

Решение галамбалаза великолепно! Это отлично сработало для меня как в 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);
}

Вы можете даже отключить контекстное меню с помощью этого хака:

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; };
}
Рафаэль
источник
0

У меня была похожая проблема с анимацией на мобильных экранах, но не на ноутбуках, когда я пытался анимировать div с помощью команды jquery animate. Поэтому я решил использовать таймер, который восстанавливал положение прокрутки окна так часто, что на первый взгляд документ казался статичным. Это решение отлично работало на мобильных устройствах с небольшим экраном, таких как Samsung Galaxy-2 или iphone-5.

Основная логика этого подхода : Таймер для установки положения прокрутки окна в исходное положение прокрутки должен быть запущен перед командой jquery animate, а затем, когда анимация завершена, нам нужно очистить этот таймер ( original scroll positionэто позиция непосредственно перед запуском анимации).

К своему приятному удивлению , я обнаружил, что документ действительно выглядел статичным в течение продолжительности анимации, если был интервал таймера 1 millisecond, к чему я стремился.

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

ДРУГОЕ РЕШЕНИЕ, которое сработало : Основываясь на ответе Мохаммада Анини на этот пост, чтобы включить / отключить прокрутку, я также обнаружил, что работает модифицированная версия кода, как показано ниже.

//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() {};
});
Сунил
источник
0

Простое решение, которое сработало для меня (временно отключив прокрутку окна).

На основании этой скрипки: http://jsfiddle.net/dh834zgw/1/

следующий фрагмент (с использованием jquery) отключит прокрутку окна:

 var curScrollTop = $(window).scrollTop();
 $('html').toggleClass('noscroll').css('top', '-' + curScrollTop + 'px');

И в вашем css:

html.noscroll{
    position: fixed;
    width: 100%;
    top:0;
    left: 0;
    height: 100%;
    overflow-y: scroll !important;
    z-index: 10;
 }

Теперь, когда вы удаляете модальный режим, не забудьте удалить класс noscroll в теге html:

$('html').toggleClass('noscroll');
вереск
источник