Jak tymczasowo wyłączyć przewijanie?


434

Korzystam z wtyczki scrollTo jQuery i chciałbym wiedzieć, czy w jakiś sposób można tymczasowo wyłączyć przewijanie elementu okna za pomocą Javascript? Powodem, dla którego chciałbym wyłączyć przewijanie jest to, że przewijanie podczas przewijania Aby się animować, robi się naprawdę brzydkie;)

Oczywiście, mógłbym zrobić $("body").css("overflow", "hidden");a następnie ustawić go z powrotem na auto, gdy animacja się zatrzyma, ale byłoby lepiej, gdyby pasek przewijania był nadal widoczny, ale nieaktywny.


12
Jeśli nadal się wyświetla, użytkownik jest szkolony, aby myśleć, że musi działać. Jeśli dawka się nie przesunie lub dawka nie zareaguje, spowoduje to przerwanie mentalnego modelu działania strony i zamieszanie. Po prostu znajdę lepszy sposób radzenia sobie z przewijaniem podczas animacji, na przykład zatrzymanie animacji.
Marcus Whybrow

Odpowiedzi:


730

scrollZdarzenie nie może być anulowane. Możesz to jednak zrobić, anulując następujące zdarzenia interakcji: przewijanie
myszą i dotykiem oraz przyciski związane z przewijaniem.

[ Działające demo ]

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

AKTUALIZACJA: naprawiono przeglądarki Chrome na komputery stacjonarne i nowoczesne przeglądarki mobilne z pasywnymi odbiornikami


114
Wskazówka dla innych deweloperów, którzy utknęli w tej pułapce: upewnij się, że usuwasz wszystkie wywołania „e.stopPropagation ()” z innych prób jQuery, aby zatrzymać przewijanie, ponieważ nie tylko to nie działa, ale także zapobiega przenikaniu zdarzenia do TEGO kodu to DZIAŁA. Mam nadzieję, że moje zmarnowane 30 minut pomoże zaoszczędzić komuś czas :)
Dirk van Bergen

4
Możesz dodać 32 (spację) do tablicy wyłączonych klawiszy (pokaż w komentarzach do kodu).
gblazex

14
Mogę przewijać tak jak zawsze: używając środkowego przycisku i poruszając myszą ... Dlatego ta sztuczka nie wpłynie na takich użytkowników jak ja;)
Denis V

11
Pasek przewijania nie jest wyłączony.
werset

8
To już nie działa w Chrome
PerrierCitror

427

Zrób to po prostu dodając klasę do treści:

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

Dodaj klasę, a następnie usuń, jeśli chcesz ponownie włączyć przewijanie, przetestowane w IE, FF, Safari i Chrome.

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

W przypadku urządzeń mobilnych musisz obsłużyć touchmovewydarzenie:

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

I cofnij powiązanie, aby ponownie włączyć przewijanie. Testowane w iOS6 i Android 2.3.3

$('body').unbind('touchmove')

4
Rozumiem! Musisz poradzić sobie ze touchmovezdarzeniem, jak w przypadku $('body').bind('touchmove', function(e){e.preventDefault()}). Edytowałem tę odpowiedź, aby uwzględnić to rozwiązanie mobilne.
MusikAnimal

3
Fajnie, po prostu upewnij się, że każde wewnętrzne przewijanie może działać w trybie modalnym dla urządzenia dotykowego. Można wykonać nakładkę tuż pod modułem i zapobiec domyślnemu ruchowi dotykiem na nakładce zamiast na ciele.
hallodom

63
Chociaż to rozwiązanie działa, ma (potencjalnie) niepożądany efekt przewijania z powrotem na górę strony.
Matt

3
Nie działało to dla mnie, chyba że moim selektorem był$('body,html')
PickYourPoison

22
To rozwiązanie działa, ale pasek przewijania znika i tworzy efekt „uderzenia” (pod osią okna), gdy zastosujesz tę klasę do ciała (na przykład)
Georgio,

57

Oto naprawdę prosty sposób:

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

W IE6 jest to trochę nerwowe.


14
Naprawdę nie wyłącza, bardziej przypomina domyślny tryb przyciągania podczas próby przewijania.
Marcus Whybrow

11
@Marcus Tak dobre, jak to możliwe, z wydarzeniem, którego nie można anulować.
sdleihssirhc

3
Mimo że nie wyłącza go naprawdę, symuluje to i to mi wystarcza.
Chris Bier

11
IMHO - najlepsza odpowiedź tutaj. Ponadto nie musisz go blokować (0, 0), wystarczy użyć bieżącej pozycji przewijania.
YemSalat

4
Ale jak możemy to włączyć?
Cybernetyczny

41

Poniższe rozwiązanie jest proste, ale czyste JavaScript (bez 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 w Safari 7.1 i IE 11. Najnowszy Chrome, Firefox, Opera ok.
Timo Kähkönen,

Wciąż trochę podskakuje na najnowszym Chrome
Jason Allshorn

Działa dobrze, w safari, chrom, ale migotał w IE
Bhuvan Arora

Jeśli to rozwiązanie nie działa w przypadku niektórych przeglądarek, oznacza to problem z przeglądarkami
Oto Shavadze,

Jak wspomniano w innej odpowiedzi, scroll-behavior: smoothrozwal to. Poza tym nie zgadzam się z Oto, że to wina przeglądarki. Zasadniczo zakładasz, że coś stanie się natychmiast, gdy w rzeczywistości jest asynchroniczne
Matt Fletcher

25

To rozwiązanie utrzyma bieżącą pozycję przewijania, gdy przewijanie jest wyłączone, w przeciwieństwie do niektórych, które skaczą użytkownika z powrotem na górę.

Opiera się na odpowiedzi Galambalazs , ale z obsługą urządzeń dotykowych i został przekształcony w pojedynczy obiekt z opakowaniem wtyczki jquery.

Demo tutaj.

Na github tutaj.

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

Cieszę się, że to przydatne. NB Edytowałem z linkiem do tego w formacie wtyczki jQuery .
Josh Harrison,

Może pomóc, jeśli przycisk wyłączania przewijania rzeczywiście działał
cameronjonesweb

@ user1672694, działa tutaj w Chrome. W której przeglądarce i na której stronie demo znalazłeś błąd? Jakieś błędy JS w konsoli?
Josh Harrison

W Chrome (38, Windows 7) nadal mogę przewijać, klikając i przytrzymując środkowy przycisk, a następnie przeciągając.
Sethi

1
Proszę zlekceważyć, okazało się, że wiązanie mousewheelzadziałało
adamj

17

Przepraszam, że odpowiedziałem na stary post, ale szukałem rozwiązania i natknąłem się na to pytanie.

Istnieje wiele obejść tego problemu, aby nadal wyświetlać pasek przewijania, na przykład nadanie kontenerowi 100% wysokości i overflow-y: scrollstylu.

W moim przypadku właśnie utworzyłem div z paskiem przewijania, który wyświetlam podczas dodawania overflow: hiddendo treści:

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

Pasek przewijania elementu musi mieć następujące style:

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

To pokazuje szary pasek przewijania, mam nadzieję, że pomoże przyszłym użytkownikom.


8

Szukałem rozwiązania tego problemu, ale nie byłem zadowolony z żadnego z powyższych rozwiązań ( pisząc tę ​​odpowiedź ), więc wymyśliłem to rozwiązanie.

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

Uważam, że to zadziałało, jeśli dodałem overflow-y: scrolldo tego .scrollDisabledstylu. W przeciwnym razie nastąpił niewielki skok, ponieważ pasek przewijania chował się za każdym razem. Oczywiście działa to tylko dla mnie, ponieważ moja strona jest wystarczająco długa, aby potrzebować paska przewijania nawet na największych ekranach.
Andrew Miner,

7

Zgodnie z postem z galambalazs dodałbym obsługę urządzeń dotykowych, pozwalając nam dotykać, ale nie przewijaj w górę lub w dół:

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

function enable_scroll() {
   ...
   document.ontouchmove = function(e){ 
     return true; 
   }
}

3
Czy na pewno jest to odpowiedź, a nie tylko komentarz do innej odpowiedzi?
IvanH

6

Począwszy od Chrome 56 i innych nowoczesnych przeglądarek, musisz dodać passive:falsedo addEventListenerpołączenia, aby preventDefaultzadziałało. Używam tego, aby zatrzymać przewijanie na telefonie komórkowym:

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

function disableScroll(){
    document.body.addEventListener('touchmove', preventDefault, { passive: false });
}
function enableScroll(){
    document.body.removeEventListener('touchmove', preventDefault, { passive: false });
}

5

Nie, nie wybrałbym obsługi zdarzeń, ponieważ:

  • nie wszystkie zdarzenia mają gwarancję dotarcia do ciała,

  • zaznaczanie tekstu i przesuwanie w dół powoduje przewijanie dokumentu,

  • jeśli w fazie zdarzenia odłączenie czegoś pójdzie nie tak, jesteś skazany.

Ugryzłem się przez to, wykonując operację kopiuj-wklej z ukrytym obszarem tekstowym i zgadnij co, strona przewija się za każdym razem, gdy robię kopię, ponieważ wewnętrznie muszę wybrać obszar tekstowy przed wywołaniem document.execCommand('copy').

W każdym razie w ten sposób idę, zauważ setTimeout():

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

Pęd miga, gdy paski przewijania znikają na chwilę, ale myślę, że jest to do przyjęcia.


4

W zależności od tego, co chcesz osiągnąć za pomocą usuniętego zwoju, możesz po prostu naprawić element, z którego chcesz usunąć zwój (po kliknięciu lub dowolnym innym wyzwalaczu, który chcesz tymczasowo wyłączyć przewijanie)

Szukałem rozwiązania „temp no scroll” i moje potrzeby to rozwiązało

zrobić klasę

.fixed{
    position: fixed;
}

potem z 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');
    };
});

Przekonałem się, że było to dość proste rozwiązanie, które działa dobrze we wszystkich przeglądarkach, a także ułatwia korzystanie z urządzeń przenośnych (np. IPhone'ów, tabletów itp.). Ponieważ element jest tymczasowo naprawiony, nie ma przewijania :)

UWAGA! W zależności od umiejscowienia elementu „contentContainer” może być konieczne dostosowanie go od lewej. Można to łatwo zrobić, dodając lewą wartość css do tego elementu, gdy stała klasa jest aktywna

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

4

Inne rozwiązanie:

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

W ten sposób zawsze masz pionowy pasek przewijania, ale ponieważ większość mojej zawartości jest dłuższa niż rzutnia, jest to dla mnie w porządku. Treść jest wyśrodkowana oddzielnym div, ale bez ponownego ustawiania marginesu w treści moja treść pozostanie po lewej stronie.

Są to dwie funkcje, których używam, aby pokazać moje popup / modal:

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

Wynik: nie można przewijać tła i nie zmienia się położenia zawartości z powodu lewego paska przewijania. Testowane z obecnymi FF, Chrome i IE 10.


To działało dla mnie i problem z przewijaniem do góry po użyciu position: naprawiono. Dziękuję!
Annia Martinez

3

Co powiesz na to? (Jeśli używasz 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() });
    }
};

nieco nerwowy, ale działa to w IE 7 (klient go używa). inne rozwiązania nie.
niki b

3

Korzystam z showModalDialog , aby wyświetlić stronę pomocniczą jako modalne okno dialogowe.

aby ukryć paski przewijania okna głównego:

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

a podczas zamykania modalnego okna dialogowego, pokazując paski przewijania okna głównego:

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

aby uzyskać dostęp do elementów w oknie głównym z okna dialogowego:

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

tylko dla osób szukających showModalDialog : (po wierszu 29 oryginalnego kodu)

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

To działało dla mnie w React, gdzie jQuery nie istnieje i gdzie React nie ma dostępu do zarządzania stanem tagu body.
Jon

3

Anulowanie wydarzenia zgodnie z przyjętą odpowiedzią jest, moim zdaniem, okropną metodą: /

Zamiast tego użyłem position: fixed; top: -scrollTop();poniżej.

Demo: https://jsfiddle.net/w9w9hthy/5/

Z mojego wyskakującego projektu 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": ""});
    }
}

Ten kod uwzględnia kwestie szerokości, wysokości, paska przewijania i pagejump.

Możliwe problemy rozwiązane za pomocą powyższego kodu:

  • szerokość, po ustaleniu pozycji ustalonej szerokość elementu HTML może być mniejsza niż 100%
  • wysokość, jak wyżej
  • pasek przewijania, po ustawieniu pozycji naprawiono zawartość strony nie ma już paska przewijania, nawet jeśli miał pasek przewijania przed skutkiem poziomego przewijania strony
  • pagejump, po ustawieniu pozycji naprawiono przewijanie strony, co powoduje, że pionowy pagejump nie jest już skuteczny

Jeśli ktoś ma jakieś poprawki do powyższego kodu blokowania / odblokowywania strony, daj mi znać, żebym mógł dodać te poprawki do mojego projektu.


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

1
To najlepsze rozwiązanie tutaj.
jfunk

@jfunk zgadzają się, prosty i zwięzły, mały kod, idealny. Dziękuję
Florent Roques

2

Mam ten sam problem, poniżej jest sposób, w jaki sobie z nim radzę.

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

Mam nadzieję, że to pomoże.


1

Opierając się na odpowiedzi Cheyenne Forbes, którą znalazłem tutaj przez fcalderan: Wyłącz wyłączenie przewijania, nie ukryć? i naprawić znikający pasek przewijania Hallodomy

CSS:

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

JS:

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

Ten kod przeskakuje cię na górę strony, ale myślę, że kod fcalderana ma obejście.


1

Wiem, że to stare pytanie, ale musiałem zrobić coś bardzo podobnego, a po pewnym czasie szukając odpowiedzi i próbując różnych podejść, skończyłem na bardzo łatwym rozwiązaniu.

Mój problem był bardzo podobny, prawie identyczny, jedyną różnicą jest to, że tak naprawdę nie musiałem pokazywać paska przewijania - musiałem tylko upewnić się, że jego szerokość będzie nadal używana, więc szerokość strony nie zmieni się podczas wyświetlania mojej nakładki .

Kiedy zaczynam przesuwać moją nakładkę na ekran, robię:

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

a po zsunięciu nakładki z ekranu robię:

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

WAŻNE: działa to doskonale, ponieważ moja nakładka jest ustawiona absolute, right: 0pxkiedy visible.


1

Najprostsza metoda to:

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

Aby cofnąć to:

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

Łatwy do wdrożenia, ale jedynym minusem jest:

  • Strona przeskoczy nieco w lewo, jeśli jest wyśrodkowana (poziomo).

Jest to spowodowane usunięciem paska przewijania i powiększeniem widoku.


1
które zresetuje pozycję przewijania
Angel David Calderaro Pacciott,

@AngelDavidCalderaroPacciott Nie, pozycja przewijania pozostanie na tej samej wysokości / odległości.
Daan

@ Daan resetuje pozycję przewijania w Chrome
Tom

@ Tom Właśnie to sprawdziłem, robi to tylko przy niektórych okazjach (gdy wysokość ciała nie jest względna w stosunku do dzieci). Spróbuj zmienić bodyna htmlzamiast.
Daan

Założę się, że nie sprawdziłeś swojego rozwiązania w Iphone, ponieważ tam overflow:hiddennie działa
Shuvo

1

Oto moje rozwiązanie, aby zatrzymać przewijanie (bez jQuery). Używam go do wyłączania przewijania, gdy pojawia się menu boczne.

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

Umieściłem 17px padding-right, aby zrekompensować zniknięcie paska przewijania. Jest to jednak problematyczne, głównie w przypadku przeglądarek mobilnych. Rozwiązany przez uzyskanie zgodnie z tym szerokości pręta .

Wszystko razem w tym piórze.



1

To najprostsze rozwiązanie, jakie do tej pory mam. I wierz mi, próbowałem wszystkich innych i to jest najłatwiejsze. Działa świetnie na urządzeniach z systemem Windows , które popychają stronę z prawej strony, aby mieć miejsce na systemowy pasek przewijania i urządzenia IOS, które nie wymagają miejsca na paski przewijania w przeglądarkach. Używając tego, nie będziesz musiał dodawać dopełnienia po prawej stronie, aby strona nie migała, gdy ukryjesz przepełnienie treści lub HTML za pomocą css .

Rozwiązanie jest dość proste, jeśli się nad tym zastanowić. Chodzi o to, aby nadać window.scrollTop () tej samej dokładnej pozycji w momencie otwarcia wyskakującego okienka. Zmień także tę pozycję, gdy zmienia się rozmiar okna (ponieważ pozycja przewijania zmienia się, gdy to nastąpi).

Więc zaczynamy...

Najpierw stwórzmy zmienną, która da ci znać, że okienko jest otwarte i nazwij go stopWindowScroll . Jeśli tego nie zrobimy, pojawi się błąd niezdefiniowanej zmiennej na stronie i ustawi się na 0 - jako nieaktywną.

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

Teraz zróbmy funkcję otwartego wyskakującego okienka, która może być dowolną funkcją w kodzie, która wyzwala dowolne wyskakujące okienko używane jako wtyczka lub niestandardowe. W tym przypadku będzie to zwykłe niestandardowe okno podręczne z prostym dokumentem po kliknięciu.

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

Więc następną rzeczą, którą robimy, jest utworzenie funkcji zamykania wyskakującego okienka, którą powtarzam ponownie, może być dowolną funkcją, którą już utworzyłeś lub używasz we wtyczce. Ważne jest to, że potrzebujemy tych 2 funkcji, aby ustawić zmienną stopWindowScroll na 1 lub 0, aby wiedzieć, kiedy jest otwarta lub zamknięta.

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

Następnie stwórzmy funkcję window.scroll, abyśmy mogli zapobiec przewijaniu, gdy wspomniany wyżej stopWindowScroll zostanie ustawiony na 1 - jako aktywny.

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

Otóż ​​to. Nie wymaga CSS, aby działał, z wyjątkiem własnych stylów strony. To działało jak urok dla mnie i mam nadzieję, że pomoże tobie i innym.

Oto działający przykład JSFiddle:

JS Fiddle Przykład

Daj mi znać, czy to pomogło. Pozdrowienia.


1

Przechowuj długość zwoju w zmiennej globalnej i przywróć ją w razie potrzeby!

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

Ten kod będzie działał na Chrome 56 i dalszych (oryginalna odpowiedź już nie działa na Chrome).

Posługiwać się DomUtils.enableScroll() aby włączyć przewijanie.

Użyj, DomUtils.disableScroll()aby wyłączyć przewijanie.

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

1

Aby zapobiec skokowi, użyłem tego

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

i w moim css

.disable-scroll {
  height: 100%;
  overflow: hidden;
  width: 100%;
  position: fixed;
}

0

Znalazłem tę odpowiedź na innej stronie :

Wyłącz przewijanie:

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

Po zamknięciu wyskakującego okienka przewiń:

$( ".popup" ).live({
    popupafterclose: function(event, ui) {
    $("body").unbind("touchmove");
}
});

To wydaje się tylko zatrzymywać przewijanie dotykowe, ale przewijanie myszy, klawisze strzałek, klawisze przewijania w górę iw dół itp. Nadal będą działać. -1
markasoftware

Te „zdarzenia” służą do przewijania dotykowego, wystarczy zastąpić dowolne potrzebne zdarzenia.
pennstump,

1
wydaje się, że jest to wykorzystywane w innej bardzo specyficznej sytuacji. popupbeforeposition? Po co to ma być? Co to ma wspólnego z tymczasowym wyłączeniem przewijania? Przynajmniej spraw, by miało to znaczenie w tej sytuacji. Wygląda na to, że skopiowałeś to bezpośrednio ze strony internetowej.
markasoftware

0

rozwiązanie galambalazs jest świetne! Działa idealnie dla mnie zarówno w Chrome, jak i Firefox. Można go również rozszerzyć, aby zapobiec domyślnemu zdarzeniu z okna przeglądarki. Powiedzmy, że robisz aplikację na płótnie. Możesz to zrobić:

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

A potem w aplikacji powiedzmy, że będziesz przetwarzać własne zdarzenia, takie jak mysz, klawiatura, zdarzenia dotykowe itd. Możesz wyłączyć zdarzenia domyślne, gdy mysz znajdzie się w obszarze roboczym, i włączyć je ponownie, gdy mysz wychodzi:

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

Możesz nawet wyłączyć menu prawego przycisku myszy dzięki temu hackowi:

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

Miałem podobny problem z animacją na ekranach telefonów komórkowych, ale nie na laptopach, kiedy próbowałem animować div za pomocą polecenia animacji jquery. Postanowiłem więc użyć timera, który tak często przywracał pozycję przewijania okna, że ​​gołym okiem dokument wydawał się statyczny. To rozwiązanie działało idealnie na małym urządzeniu mobilnym, takim jak Samsung Galaxy-2 lub iPhone-5.

Główna logika tego podejścia : Timer ustawiający pozycję przewijania okna na pierwotną pozycję przewijania powinien zostać uruchomiony przed poleceniem animacji jquery, a następnie po zakończeniu animacji musimy wyczyścić ten timer ( original scroll positionjest to pozycja tuż przed rozpoczęciem animacji).

Z przyjemnością zdziwiłem się, że dokument rzeczywiście wydawał się statyczny podczas trwania animacji, jeśli interwał czasowy był taki 1 millisecond, do czego dążyłem.

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

KOLEJNE ROZWIĄZANIE, które działało : Na podstawie odpowiedzi Mohammada Aniniego pod tym postem, aby włączyć / wyłączyć przewijanie, odkryłem również, że zmodyfikowana wersja kodu, jak poniżej, działała.

//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

Proste rozwiązanie, które zadziałało dla mnie (tymczasowe wyłączenie przewijania okna).

Na podstawie tego skrzypka: http://jsfiddle.net/dh834zgw/1/

następujący fragment kodu (używając jquery) wyłączy przewijanie okna:

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

I w twoim css:

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

Teraz, kiedy usuwasz modal, nie zapomnij usunąć klasy noscroll z tagu html:

$('html').toggleClass('noscroll');
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.