Jak programowo wyłączyć przewijanie stron za pomocą jQuery


163

Korzystając z jQuery, chciałbym wyłączyć przewijanie treści:

Mój pomysł to:

  1. Zestaw body{ overflow: hidden;}
  2. Uchwyć prąd scrollTop();/scrollLeft()
  3. Powiązanie ze zdarzeniem body scroll, ustaw scrollTop / scrollLeft na przechwyconą wartość.

Czy jest lepszy sposób?


Aktualizacja:

Proszę zobaczyć mój przykład i powód, dla którego jest to http://jsbin.com/ikuma4/2/edit

Wiem, że ktoś pomyśli „dlaczego nie używa po prostu position: fixedna panelu?”.

Nie sugeruj tego, bo mam inne powody.


7
"Czy jest lepszy sposób?" - inne niż pozwalanie przeglądarce na normalne działanie?
Fenton,

22
„melodramatycznie”?
Mike Weller,

6
Może chodziło o programowo? Ponieważ jest to najlepsza propozycja korekty pisowni w przeglądarce Firefox dla „programowo”
Michael Shimmins

4
Ten wątek będzie \ b \
Cipi,

3
@Sohnee wyłącza przewijanie! == bad
Mansiemans

Odpowiedzi:


136

Jedyny sposób, w jaki to zrobiłem, jest podobny do tego, co opisałeś:

  1. Chwyć aktualną pozycję przewijania (nie zapomnij o osi poziomej!).
  2. Ustaw przepełnienie na ukryte (prawdopodobnie chcesz zachować poprzednią wartość przepełnienia).
  3. Przewiń dokument do zapisanej pozycji przewijania za pomocą scrollTo ().

Następnie, gdy będziesz gotowy, aby ponownie zezwolić na przewijanie, cofnij to wszystko.

Edycja: nie ma powodu, dla którego nie mogę podać kodu, ponieważ zadałem sobie trud, aby go wykopać ...

// lock scroll position, but retain settings for later
var scrollPosition = [
  self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
  self.pageYOffset || document.documentElement.scrollTop  || document.body.scrollTop
];
var html = jQuery('html'); // it would make more sense to apply this to body, but IE7 won't have that
html.data('scroll-position', scrollPosition);
html.data('previous-overflow', html.css('overflow'));
html.css('overflow', 'hidden');
window.scrollTo(scrollPosition[0], scrollPosition[1]);


// un-lock scroll position
var html = jQuery('html');
var scrollPosition = html.data('scroll-position');
html.css('overflow', html.data('previous-overflow'));
window.scrollTo(scrollPosition[0], scrollPosition[1])

2
zobacz jsbin.com/ikuma4/2/edit i wyjaśnij mi powód, dla którego twój jest lepszy? czy coś mi brakuje (pytam, ponieważ nie widzę żadnego powodu długości Twojej odpowiedzi w porównaniu z moim przykładem)
Hailwood

3
Twoje podejście nie działa w IE7. Ja też tego spróbowałem. Problem polega na tym, że nie reaguje wystarczająco szybko na zdarzenie przewijania. Pozwala przewijać dokument, a następnie cofa go, gdy JS resetuje pozycję przewijania z powrotem tam, gdzie chcesz.
tfe

1
Ponadto, jeśli w treści pojawiło się coś innego niż treść auto, zostanie ono nadpisane. Musiałem zachować istniejące ustawienie, więc to również zwiększa koszty.
tfe

Czy ktoś wie, dlaczego samo stylizowanie htmli za bodypomocą overflow: hiddenjest niewystarczające? Nadal potrzebujemy obsługi zdarzeń.
kpozin

4
To fantastyczna odpowiedź. Aby działał na urządzeniach dotykowych, zapoznaj się z odpowiedzią.
Patrick

235

Spowoduje to całkowite wyłączenie przewijania:

$('html, body').css({
    overflow: 'hidden',
    height: '100%'
});

Przywrócić:

$('html, body').css({
    overflow: 'auto',
    height: 'auto'
});

Przetestowałem to na Firefoksie i Chrome.


18
działa zgodnie z oczekiwaniami. Dzięki! To powinna być zaakceptowana odpowiedź!
Dave Chen

6
Nadal przewija się środkowym przyciskiem myszy na chrome.
Lothar

16
Spowoduje to utratę aktualnej pozycji przewijania. OP wyraźnie wspomniał o przechwytywaniu pozycji przewijania, więc zakładam, że tego wymagał. W każdym razie tego potrzebuję, więc ma to dla mnie ograniczone zastosowanie
zerm

7
PS Pominięcie height: 100%efektywnie blokuje przewijanie w aktualnej pozycji bez skakania - przynajmniej na najnowszym Chrome.
zerm

2
To NIE jest poprawna odpowiedź. Pozycja przewijania nie została uchwycona
taylorcressy

43

Spróbuj tego

$('#element').on('scroll touchmove mousewheel', function(e){
  e.preventDefault();
  e.stopPropagation();
  return false;
})

właśnie tego szukałem ... prawie. W każdym razie, aby wyłączyć go podczas klawiszy strzałek?
Cody,

2
@Cody - połącz to z przepełnieniem css: hidden
Darius.V

2
@cubbiu jak to odwrócić?
Meer

3
Możesz skorzystać$('#element').off('scroll touchmove mousewheel');
arnuschky

1
Świetne rozwiązanie. Chociaż jak wyłączyć bodyprzewijanie, a jednocześnie zezwolić na przewijanie w obrębie innych elementów podrzędnych, które mają overflow: scroll?
Fizzix

27

Podaję tylko małe dostrojenie rozwiązania przez tfe . W szczególności dodałem dodatkową kontrolę, aby upewnić się, że nie ma przesunięcia zawartości strony (czyli przesunięcia strony ), gdy pasek przewijania jest ustawiony na hidden.

Dwie funkcje JavaScript lockScroll()i unlockScroll()można zdefiniować odpowiednio, aby zablokować i odblokować przewijanie strony.

function lockScroll(){
    $html = $('html'); 
    $body = $('body'); 
    var initWidth = $body.outerWidth();
    var initHeight = $body.outerHeight();

    var scrollPosition = [
        self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
        self.pageYOffset || document.documentElement.scrollTop  || document.body.scrollTop
    ];
    $html.data('scroll-position', scrollPosition);
    $html.data('previous-overflow', $html.css('overflow'));
    $html.css('overflow', 'hidden');
    window.scrollTo(scrollPosition[0], scrollPosition[1]);   

    var marginR = $body.outerWidth()-initWidth;
    var marginB = $body.outerHeight()-initHeight; 
    $body.css({'margin-right': marginR,'margin-bottom': marginB});
} 

function unlockScroll(){
    $html = $('html');
    $body = $('body');
    $html.css('overflow', $html.data('previous-overflow'));
    var scrollPosition = $html.data('scroll-position');
    window.scrollTo(scrollPosition[0], scrollPosition[1]);    

    $body.css({'margin-right': 0, 'margin-bottom': 0});
}

gdzie założyłem, że <body>nie ma początkowego depozytu zabezpieczającego.

Zauważ, że chociaż powyższe rozwiązanie działa w większości praktycznych przypadków, nie jest ostateczne, ponieważ wymaga dalszego dostosowania dla stron, które zawierają na przykład nagłówek z position:fixed. Przejdźmy do tego szczególnego przypadku z przykładem. Przypuśćmy, że tak

<body>
<div id="header">My fixedheader</div>
<!--- OTHER CONTENT -->
</body>

z

#header{position:fixed; padding:0; margin:0; width:100%}

Następnie należałoby dodać następujących funkcji lockScroll()oraz unlockScroll():

function lockScroll(){
    //Omissis   


    $('#header').css('margin-right', marginR);
} 

function unlockScroll(){
    //Omissis   

    $('#header').css('margin-right', 0);
}

Na koniec zwróć uwagę na możliwą wartość początkową marginesów lub wypełnień.


4
Masz błąd w swoim javascript $ body.css ({'margin-right': 0, 'margin-bottom', 0}); powinno być $ body.css ({'margin-right': 0, 'margin-bottom': 0});
Johansrk

Właściwie po prostu użyj marginRighti marginLeft:)
Martijn

25

możesz użyć tego kodu:

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

8
Nadal możesz używać środkowego przycisku myszy do przewijania.
Roger Far

2
Nie, to jest w porządku i nie ma z tym przewijania!
mr.soroush

Jeśli używasz dodatkowego CSS, MOŻESZ całkowicie wyłączyć przewijanie, zobacz moją odpowiedź, aby uzyskać więcej informacji.
gitaarik

21

Aby wyłączyć przewijanie, spróbuj tego:

var current = $(window).scrollTop();
$(window).scroll(function() {
    $(window).scrollTop(current);
});

zresetować:

$(window).off('scroll');

To było fantastyczne rozwiązanie na to, czego potrzebowałem.
Terry Carter

@EveryScreamer nie, to sprawia, że ​​ekran drży jak szalony. Próbuję znaleźć obejście.
Telarian

5

Napisałem wtyczkę jQuery do obsługi tego: $ .disablescroll .

Zapobiega przewijaniu w przypadku zdarzeń związanych z kółkiem myszy, ruchem dotykowym i naciśnięciem klawisza, takich jak Page Down.

Tutaj jest demo .

Stosowanie:

$(window).disablescroll();

// To re-enable scrolling:
$(window).disablescroll("undo");

Próbowałem użyć twojej wtyczki disablescroll (), aby tymczasowo wyłączyć przewijanie po usłyszeniu zdarzenia kółka myszy / przewijania, ale to nie działa. Czy znasz sposób na osiągnięcie tego efektu?
żółty święty

@JB Prawdopodobnie mogę pomóc, ale komentarze nie są najlepszym miejscem. Dołącz do mnie na czacie o przepełnieniu stosu, a zobaczę, co mogę zrobić: chat.stackoverflow.com/rooms/55043/disablescroll-usage
Josh Harrison.

Przepraszam, ale ta wtyczka nie działa nawet w twoim jsfiddle.
markj

Możesz mi pomóc w sprawdzeniu tego, mówiąc mi, w której przeglądarce / platformie nie działa?
Josh Harrison


4

Jedna linijka wyłączająca przewijanie, w tym środkowy przycisk myszy.

$(document).scroll(function () { $(document).scrollTop(0); });

edycja : i tak nie ma potrzeby korzystania z jQuery, poniżej to samo co powyżej w waniliowym JS (to znaczy bez frameworków, tylko JavaScript):

document.addEventListener('scroll', function () { this.documentElement.scrollTop = 0; this.body.scrollTop = 0; })

this.documentElement.scrollTop - standard

this.body.scrollTop - zgodność z IE




3

Ktoś wysłał ten kod, który ma problem z nie zachowaniem pozycji przewijania po przywróceniu. Powodem jest to, że ludzie zwykle stosują go do html i body lub tylko do body, ale powinien być stosowany tylko do html. W ten sposób po przywróceniu pozycja przewijania zostanie zachowana:

$('html').css({
    'overflow': 'hidden',
    'height': '100%'
});

Przywrócić:

$('html').css({
    'overflow': 'auto',
    'height': 'auto'
});

nie 'overflow': 'auto',używać'overflow': 'initial',
evtuhovdo

2

Może to działać lub nie do Twoich celów, ale możesz rozszerzyć jScrollPane, aby uruchomić inne funkcje, zanim wykona przewijanie. Tylko trochę to przetestowałem, ale mogę potwierdzić, że możesz wskoczyć i całkowicie zapobiec przewijaniu. Wszystko co zrobiłem to:

  • Pobierz plik demonstracyjny ZIP: http://github.com/vitch/jScrollPane/archives/master
  • Otwórz demo „Wydarzenia” (events.html)
  • Edytuj go, aby użyć niezminifikowanego źródła skryptu: <script type="text/javascript" src="script/jquery.jscrollpane.js"></script>
  • Wewnątrz jquery.jscrollpane.js wstaw „return”; w linii 666 (pomyślny numer linii! ale w przypadku, gdy twoja wersja różni się nieznacznie, jest to pierwsza linia positionDragY(destY, animate)funkcji

Uruchom events.html, a zobaczysz normalnie przewijane okienko, które z powodu interwencji w kodowanie nie będzie się przewijać.

W ten sposób możesz kontrolować wszystkie paski przewijania przeglądarki (patrz fullpage_scroll.html).

Więc prawdopodobnie następnym krokiem jest dodanie wywołania do innej funkcji, która uruchamia się i wykonuje magię zakotwiczenia, a następnie decyduje, czy kontynuować przewijanie, czy nie. Masz również wywołania API do ustawiania scrollTop i scrollLeft.

Jeśli chcesz uzyskać więcej pomocy, napisz, do czego zmierzasz!

Mam nadzieję, że to pomogło.



1

Jeśli chcesz tylko wyłączyć przewijanie za pomocą nawigacji za pomocą klawiatury, możesz zastąpić zdarzenie keydown.

$(document).on('keydown', function(e){
    e.preventDefault();
    e.stopPropagation();
});

1

Wypróbuj ten kod:

    $(function() { 
        // ...

        var $body = $(document);
        $body.bind('scroll', function() {
            if ($body.scrollLeft() !== 0) {
                $body.scrollLeft(0);
            }
        });

        // ...
    });

0

Możesz zakryć okno przewijalnym elementem div, aby zapobiec przewijaniu zawartości strony. A ukrywając i pokazując, możesz zablokować / odblokować zwój.

Zrób coś takiego:

#scrollLock {
    width: 100%;
    height: 100%;
    position: fixed;
    overflow: scroll;
    opacity: 0;
    display:none
}

#scrollLock > div {
    height: 99999px;
}

function scrollLock(){
    $('#scrollLock').scrollTop('10000').show();
}

function scrollUnlock(){
    $('#scrollLock').hide();
}

7
Nie używaj skrótów, takich jak „u” i „coś”. Poświęć trochę czasu na poprawną pisownię, aby była czytelna.
Tin Man

0

Dla osób, które mają wyśrodkowane układy (przez margin:0 auto;), oto połączenie position:fixedrozwiązania wraz z proponowanym rozwiązaniem @tfe .

Skorzystaj z tego rozwiązania, jeśli występuje przyciąganie stron (ze względu na wyświetlanie / ukrywanie paska przewijania).

// lock scroll position, but retain settings for later
var scrollPosition = [
    window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
    window.pageYOffset || document.documentElement.scrollTop  || document.body.scrollTop
];
var $html = $('html'); // bow to the demon known as MSIE(v7)
$html.addClass('modal-noscroll');
$html.data('scroll-position', scrollPosition);
$html.data('margin-top', $html.css('margin-top'));
$html.css('margin-top', -1 * scrollPosition[1]);

…w połączeniu z…

// un-lock scroll position
var $html = $('html').removeClass('modal-noscroll');
var scrollPosition = $html.data('scroll-position');
var marginTop = $html.data('margin-top');
$html.css('margin-top', marginTop);
window.scrollTo(scrollPosition[0], scrollPosition[1])

… I wreszcie CSS dla .modal-noscroll

.modal-noscroll
{
    position: fixed;
    overflow-y: scroll;
    width: 100%;
}

Zaryzykowałbym stwierdzenie, że jest to bardziej właściwe rozwiązanie niż jakiekolwiek inne dostępne rozwiązania, ale nie przetestowałem go jeszcze tak dokładnie…: P


Edycja: pamiętaj, że nie mam pojęcia, jak źle może to działać (czytaj: wysadzić) na urządzeniu dotykowym.


0

Możesz także użyć do tego DOM. Powiedzmy, że masz funkcję, którą nazywasz w ten sposób:

function disable_scroll() {
document.body.style.overflow="hidden";
}

I to wszystko! Mam nadzieję, że to pomoże oprócz wszystkich innych odpowiedzi!


0

Oto, co ostatecznie zrobiłem:

CoffeeScript:

    $("input").focus ->
        $("html, body").css "overflow-y","hidden"
        $(document).on "scroll.stopped touchmove.stopped mousewheel.stopped", (event) ->
            event.preventDefault()

    $("input").blur ->
        $("html, body").css "overflow-y","auto"
        $(document).off "scroll.stopped touchmove.stopped mousewheel.stopped"

JavaScript:

$("input").focus(function() {
 $("html, body").css("overflow-y", "hidden");
 $(document).on("scroll.stopped touchmove.stopped mousewheel.stopped", function(event) {
   return event.preventDefault();
 });
});

$("input").blur(function() {
 $("html, body").css("overflow-y", "auto");
 $(document).off("scroll.stopped touchmove.stopped mousewheel.stopped");
});

0

Nie jestem pewien, czy ktoś wypróbował moje rozwiązanie. Ten działa na całym body / html, ale bez wątpienia można go zastosować do dowolnego elementu, który uruchamia zdarzenie przewijania.

Po prostu włącz i wyłącz scrollLock, jeśli potrzebujesz.

var scrollLock = false;
var scrollMem = {left: 0, top: 0};

$(window).scroll(function(){
    if (scrollLock) {
        window.scrollTo(scrollMem.left, scrollMem.top);
    } else {
        scrollMem = {
            left: self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
            top: self.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
        };
    }
});

Oto przykład JSFiddle

Mam nadzieję, że ten komuś pomoże.


Ten działa tak, jak powinien, z jednym wyjątkiem. Kiedy zwój jest zablokowany, a ja przewijam, trochę drga, zanim faktycznie
zablokuje

0

Myślę, że najlepszym i czystym rozwiązaniem jest:

window.addEventListener('scroll',() => {
    var x = window.scrollX;
    var y = window.scrollY;
    window.scrollTo(x,y);
});

A z jQuery:

$(window).on('scroll',() => {
    var x = window.scrollX;
    var y = window.scrollY;
    window.scrollTo(x,y)
})

Ten detektor zdarzeń powinien blokować przewijanie. Po prostu je usuń, aby ponownie włączyć przewijanie

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.