Czy można animować scrollTop za pomocą jQuery?


226

Chcę płynnie przewijać w dół. Nie chcę do tego pisać funkcji - szczególnie jeśli jQuery już ją ma.

Odpowiedzi:


463

Możesz po prostu skorzystać z .animate()tej scrollTopwłaściwości:

$("html, body").animate({ scrollTop: "300px" });

Bardzo fajnie .. nie trzeba do tego używać wtyczek.
Amol M. Kulkarni

15
Dlaczego potrzebujesz obu htmli body? Jest tu pewien wgląd: stackoverflow.com/questions/2123690/… , ale nie jest to pełna odpowiedź.
Haralan Dobrev

28
body jest używane przez webkit, html jest używany przez firefox.
Jory

2
FYI: Jeśli <html>ma overflow-x:hidden;to ożywione nie będzie działać. (Nie może pracować dla overflow-y:hidden, i overflow:hidden, ale nie testowałem.
collinhaines

1
Myślę, że bodydziałał w Chrome na początku tego roku, ale teraz musi tak być html.
Nick Davies,

73

Odpowiedź Nicka działa świetnie. Zachowaj ostrożność przy określaniu funkcji complete () wewnątrz wywołania animate (), ponieważ zostanie ona wykonana dwukrotnie, ponieważ zadeklarowano dwa selektory (html i body).

$("html, body").animate(
    { scrollTop: "300px" },
    {
        complete : function(){
            alert('this alert will popup twice');
        }
    }
);

Oto jak uniknąć podwójnego oddzwaniania.

var completeCalled = false;
$("html, body").animate(
    { scrollTop: "300px" },
    {
        complete : function(){
            if(!completeCalled){
                completeCalled = true;
                alert('this alert will popup once');
            }
        }
    }
);

1
Pytanie brzmi: dlaczego miałbyś animować html, body, a nie tylko body?
Lior

21
Ponieważ w zależności od przeglądarki możesz animować ciało LUB HTML. Animując ZARÓWNO, obejmujesz więcej przeglądarek.
Bene

Ale w tym przypadku wyskakuje tak naprawdę tylko raz, także jeśli trzeba go wywoływać wielokrotnie (zdarzenie kliknięcia na przycisku) lub czy coś mi umknęło?
HoGo,

Tak, w tym przypadku wyskakuje tylko raz. Jeśli musisz wielokrotnie animować, ustaw zmienną completeCalled na lokalną dla funkcji zwrotnej, która wykonuje funkcję animacji. W ten sposób wyskakuje wyskakujące okienko tylko raz po kliknięciu, ale wyskakuje ponownie (tylko raz) po ponownym kliknięciu.
Kita,

Aby zapobiec uruchamianiu funkcji podwójnego oddzwaniania, możesz użyć die()funkcji przed live()wywołaniem funkcji. Gwarantuje to, że Twój przewodnik live()zostanie wywołany tylko raz.
Lord Nighton

27

Odpowiedź Nicka działa świetnie, a ustawienia domyślne są dobre, ale możesz pełniej kontrolować przewijanie, wykonując wszystkie ustawienia opcjonalne.

oto jak to wygląda w interfejsie API:

.animate( properties [, duration] [, easing] [, complete] )

więc możesz zrobić coś takiego:

.animate( 
    {scrollTop:'300px'},
    300,
    swing,
    function(){ 
       alert(animation complete! - your custom code here!); 
       } 
    )

tutaj jest strona interfejsu API funkcji jQuery .animate: http://api.jquery.com/animate/


15

Jak wspomniała Kita, istnieje problem z uruchamianiem wielu wywołań zwrotnych, gdy animujesz zarówno „html”, jak i „body”. Zamiast animować oba i blokować kolejne wywołania zwrotne, wolę użyć niektórych podstawowych funkcji wykrywania i animować tylko właściwość scrollTop pojedynczego obiektu.

Zaakceptowana odpowiedź w tym drugim wątku daje pewien wgląd w właściwość scrollTop obiektu, którą powinniśmy spróbować animować: pageYOffset Scrolling and Animation w IE8

// UPDATE: don't use this... see below
// only use 'body' for IE8 and below
var scrollTopElement = (window.pageYOffset != null) ? 'html' : 'body';

// only animate on one element so our callback only fires once!
$(scrollTopElement).animate({ 
        scrollTop: '400px' // vertical position on the page
    },
    500, // the duration of the animation 
    function() {       
        // callback goes here...
    })
});

AKTUALIZACJA - - -

Powyższa próba wykrycia funkcji kończy się niepowodzeniem. Wygląda na to, że nie ma jednego wiersza sposobu, ponieważ właściwość pageYOffset w przeglądarkach typu webkit zawsze zwraca zero, gdy występuje typ dokumentu. Zamiast tego znalazłem sposób na skorzystanie z obietnicy wykonania pojedynczego wywołania zwrotnego za każdym razem, gdy animacja zostanie wykonana.

$('html, body')
    .animate({ scrollTop: 100 })
    .promise()
    .then(function(){
        // callback code here
    })
});

1
Używanie promise () tutaj jest genialne.
Allan Bazinet

To wymaga więcej pozytywnych opinii. Nigdy wcześniej nie widziałem takiej obietnicy i właśnie tego szukam co kilka miesięcy. Jak powiedział Allan, geniusz.
Tortilaman

14

Mam coś, co uważam za lepsze rozwiązanie niż $('html, body')hack.

Nie jest to jedna linijka, ale miałem problem z $('html, body')tym, że jeśli zalogujesz się $(window).scrollTop()podczas animacji, zobaczysz, że wartość przeskakuje wszędzie, czasem o setki pikseli (chociaż nie widzę czegoś takiego dzieje się wizualnie). Potrzebowałem, aby wartość była przewidywalna, aby móc anulować animację, jeśli użytkownik złapie pasek przewijania lub zakręci kółko myszy podczas automatycznego przewijania.

Oto funkcja sprawnie animująca przewijanie:

function animateScrollTop(target, duration) {
    duration = duration || 16;
    var scrollTopProxy = { value: $(window).scrollTop() };
    if (scrollTopProxy.value != target) {
        $(scrollTopProxy).animate(
            { value: target }, 
            { duration: duration, step: function (stepValue) {
                var rounded = Math.round(stepValue);
                $(window).scrollTop(rounded);
            }
        });
    }
}

Poniżej znajduje się bardziej złożona wersja, która anuluje animację podczas interakcji użytkownika, a także odświeża ją aż do osiągnięcia wartości docelowej, co jest przydatne, gdy próbujesz ustawić scrollTop natychmiast (np. Po prostu dzwoniąc $(window).scrollTop(1000)- z mojego doświadczenia, to nie działa 50% czasu.)

function animateScrollTop(target, duration) {
    duration = duration || 16;

    var $window = $(window);
    var scrollTopProxy = { value: $window.scrollTop() };
    var expectedScrollTop = scrollTopProxy.value;

    if (scrollTopProxy.value != target) {
        $(scrollTopProxy).animate(
            { value: target },
            {
                duration: duration,

                step: function (stepValue) {
                    var roundedValue = Math.round(stepValue);
                    if ($window.scrollTop() !== expectedScrollTop) {
                        // The user has tried to scroll the page
                        $(scrollTopProxy).stop();
                    }
                    $window.scrollTop(roundedValue);
                    expectedScrollTop = roundedValue;
                },

                complete: function () {
                    if ($window.scrollTop() != target) {
                        setTimeout(function () {
                            animateScrollTop(target);
                        }, 16);
                    }
                }
            }
        );
    }
}

7

Miałem problemy, w których animacja zawsze zaczynała się od góry strony po odświeżeniu strony w innych przykładach.

Naprawiłem to, nie animując bezpośrednio css, ale raczej wzywając window.scrollTo();na każdym kroku:

$({myScrollTop:window.pageYOffset}).animate({myScrollTop:300}, {
  duration: 600,
  easing: 'swing',
  step: function(val) {
    window.scrollTo(0, val);
  }
});

To również htmlomija bodyproblem vs, ponieważ używa JavaScript w przeglądarce.

Zajrzyj na http://james.padolsey.com/javascript/fun-with-jquerys-animate/, aby uzyskać więcej informacji o tym, co możesz zrobić z funkcją animacji jQuery.


5

Możesz użyć animacji jQuery do przewijania strony o określonym czasie trwania:

$("html, body").animate({scrollTop: "1024px"}, 5000);

gdzie 1024px to przesunięcie przewijania, a 5000 to czas trwania animacji w milisekundach.


Świetna odpowiedź! Cieszę się, że uwzględniłeś opcję czasu trwania. Chciałem tylko dodać, że to $("html, body").animate({scrollTop: 1024}, 5000);również działa.
Ryan Taylor

4

Wypróbuj wtyczkę scrollTo .


Wygląda na to, że scrollTo nie jest już projektem w tej witrynie.
Jim

Kod do osiągnięcia tego celu jest bardzo prosty. Dlaczego dodajesz wtyczkę, aby zrobić coś, co możesz zrobić za pomocą jednego wiersza kodu?
Gavin

4
Cztery lata temu nie było to takie proste .. :)
Tatu Ulmanen

4
$(".scroll-top").on("click", function(e){
   e.preventDefault();
   $("html, body").animate({scrollTop:"0"},600);
});

1

Jeśli chcesz przejść na koniec strony (nie musisz przewijać w dół), możesz użyć:

$('body').animate({ scrollTop: $(document).height() });

0

Ale jeśli naprawdę chcesz dodać animację podczas przewijania, możesz wypróbować moją prostą wtyczkę ( AnimateScroll ), która obecnie obsługuje ponad 30 stylów łagodzenia


-3

kod przeglądarki jest następujący:

$(window).scrollTop(300); 

jest bez animacji, ale działa wszędzie


6
Szukałem sposobu „ożywienia scrollTop za pomocą jQuery?” Odpowiedź „bez animacji” nie jest odpowiedzią.
Bryan Field
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.