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.

Bryan Field
źródło

Odpowiedzi:

463

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

$("html, body").animate({ scrollTop: "300px" });
Nick Craver
źródło
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');
            }
        }
    }
);
Kita
źródło
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/

pionier
źródło
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
    })
});
Stephen
źródło
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);
                    }
                }
            }
        );
    }
}
John Starr Dewar
źródło
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.

komplementarny
źródło
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.

Alessandro Pirovano
źródło
Ś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 .

Tatu Ulmanen
źródło
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);
});
Rubel Hossain
źródło
1

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

$('body').animate({ scrollTop: $(document).height() });
Mała mrówka
źródło
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

Ram Patra
źródło
-3

kod przeglądarki jest następujący:

$(window).scrollTop(300); 

jest bez animacji, ale działa wszędzie

użytkownik2760861
źródło
6
Szukałem sposobu „ożywienia scrollTop za pomocą jQuery?” Odpowiedź „bez animacji” nie jest odpowiedzią.
Bryan Field