Ta strona używa ciasteczek (cookies), dzięki którym nasz serwis może działać lepiej. Dowiedz się więcej OK, rozumiem
WebHelp.pl Warsztat Artykuły jQuery - animacje

Warsztat / Artykuły i tutoriale

jQuery - animacje

Rafał Kukawski 20 czerwca 2013 komentarze ()

W poprzednim artykule na temat jQuery przebrnęliśmy przez moduł zdarzeniowy. Tym razem zajmiemy się animacjami. Moduł ten stanowi kolejny rozbudowany element biblioteki.

.animate()

U podstaw modułu animacyjnego stoi funkcja animate. Animować możemy dowolne numeryczne (także z jednostką wielkości, np. 100px) własności CSS elementów oraz niektóre JavaScriptowe, też numeryczne, własności elementów, typu scrollTop czy scrollLeft.

Przykładowe wywołanie funkcji animate może wyglądać następująco.

Kod: Zaznacz cały
$("#test").animate({
    width: 500,
    height: 300
}, 400, "swing", function () {
    console.log("Koniec animacji");
});

JS Bin

Pierwszy parametr jest najbardziej interesujący, bo w nim informujemy jQuery, które własności obiektu chcemy animować. W powyższym przykładzie chcemy płynnie zmienić szerokość i wysokość elementu aż do osiągnięcia wartości 500px i 300px.

W pozostałych parametrach definiujemy czas trwania animacji (tutaj 400 milisekund), funkcję przejścia od wartości początkowych do końcowych oraz funkcję, która zostanie wywołana po zakończonej animacji.

Z wszystkich parametrów, obowiązkowy jest tylko pierwszy. Pozostałe można do woli opuszczać, np. można przekazać tylko funkcję wywołaną po zakończonej animacji.

Kod: Zaznacz cały
$("#animuj-mnie").animate({
    width: 500,
    height: 300
}, function () {
    console.log("Koniec animacji");
});

Alternatywnie można wywołać animate z dwoma parametrami. Pierwszy to nadal obiekt z własnościami, które mamy zamiar animować, zaś drugi to opcje. Korzystając z tej możliwości, powyższe wywołanie można zapisać jako:

Kod: Zaznacz cały
$("#animuj-mnie").animate({
    width: 150,
    height: 100
}, {
   duration: 400,
    easing: "swing",
    complete: function () {
        console.log("Koniec animacji");
    }
});

Korzystając z alternatywnego zapisu, mamy dostęp do jeszcze większej liczby opcji. Przykładowo, można zdefiniować easing function dla każdej animowanej własności z osobna.

Kod: Zaznacz cały
$("#animuj-mnie").animate({
    width: 150,
    height: 100
}, {
    specialEasing: {
        width: "swing",
        height: "linear"
    }
});

Kolejną opcją, którą możemy ustawić jest, czy animacja ma być kolejkowana i do jakiej kolejki ma trafić. O kolejkach będziemy pisać szczegółowo nieco niżej.

Pozostałe opcje to różnego rodzaju callbacki, wywoływane w ściśle określonych momentach animacji – complete, done, fail, always, step, progress.

Pierwszy parametr, ale inaczej

Ponadto, co zostało wyżej opisane, animate oferuje dodatkowe możliwości w zapisie pierwszego parametru.

Jeśli chcemy skrócić sobie nieco definiowanie funkcji przejścia dla własności, można zamiast opcji specialEasing, podać tę funkcję bezpośrednio przy wartości końcowej.

Kod: Zaznacz cały
$("#animuj-mnie").animate({
    width: [150, "swing"],
    height: [100, "linear"]
});

Dodatkowo, jeśli chcemy zmienić wartość własności względem bieżącej, nie trzeba samemu kalkulować wartości końcowej. Wystarczy podać zmianę, która ma nastąpić, np.

Kod: Zaznacz cały
$("#animuj-mnie").animate({
    width: "+=200",
    height: "-=100"
});

Funkcja easing

Domyślnie w jQuery mamy dostępne 2 typy funkcji easing – swing (domyślna) oraz linear. Jeśli interesują nas inne funkcje przejścia, wystarczy skorzystać z gotowców typu jQuery UI.

W uproszczeniu, zadaniem tej funkcji jest wyznaczenie wartości animowanej właściwości w określonym momencie animacji.

Przykładowo, jeśli animujemy własność width z 0 do 200px przez 1 sekundę z użyciem liniowej funkcji, to po 250 milisekundach (25% ustalonego czasu), width będzie miało wartość 50px, w połowie animacji – 100px, przy 75% – 150px, przy 100% – 200px.

Poniższy przykład prezentuje wpływ funkcji easing na animację.

JS Bin

Czas trwania animacji

Długość animacji ustalamy w drugim parametrze funkcji animate, w postaci wartości liczbowej lub jako własność duration obiektu konfiguracyjnego. Jednostką wielkości jest tutaj milisekunda.

Kod: Zaznacz cały
$("#test").animate({ width: 500 }, 1000); // 1-sekundowa animacja
$("#test").animate({ width: 500 }, { duration: 1000 }); // to samo co wyżej

W razie pominięcia tego detalu, jQuery będzie wykonywał 400-milisekundowe animacje. Oprócz wartości liczbowej, dozwolone są specjalne wartości tekstowe – "slow" i "fast", które oznaczają kolejno 600 i 200 milisekund.

Callbacki

Callbacki, które możemy rejestrować zostają wywołane w różnych etapach trwania animacji. Bez wątpienia, najczęściej użyjemy tych wywoływanych po zakończonej animacji. Ale nawet callbacki postępu mogą okazać się przydatne.

complete

Wywoływany po zakończeniu animacji. W przypadku przerwania animacji, callback zostanie wywołany tylko, gdy zatrzymaniu towarzyszy przeskok do wartości końcowej. Do callbacku nie zostaną przekazane żadne parametry, jedynie this będzie wskazywać na animowany element.

Callback ten jest wywoływany raz dla każdego animowanego elementu. Przykładowo, poniższy kod wykonuje animację na dwóch elementach, dlatego w konsoli zobaczymy 2 raporty o wykonaniu funkcji.

Kod: Zaznacz cały
$("#raz, #dwa").animate({
    width: 500,
    height: 500
}, function () {
    console.log("complete", this.id);
});

Gdyby sprawdzić, czy element jest nadal zaznaczony jako animowany, to otrzymamy false.

Kod: Zaznacz cały
$("#raz, #dwa").animate({
    width: 500,
    height: 500
}, function () {
    console.log("complete", this.id, $(this).is(":animated"));
});

done, fail, always

Tytułowe 3 callbacki są stosunkowo nowe w jQuery. Zostały wprowadzone po przejściu części modułów jQuery na model Promise/Deferred, popularny w zarządzaniu asynchronicznym kodem.

Krótko o Deferred/Promise

Model Deferred/Promise polega na tym, że dla każdej asynchronicznej akcji tworzony jest obiekt Deferred, który przyjmuje 3 stany. Początkowym stanem jest pending, czyli akcja jest w toku. Pozostałe 2 stany to resolved (zakończony sukcesem) oraz rejected (zakończony porażką). Obiekt ten posiada metody sterujące stanem (resolve, reject) oraz możliwość rejestrowania callbacków dla sukcesu i porażki. Gdy nastąpi zmiana stanu na resolved, wywołane zostaną wszystkie zarejestrowane dla tego stanu callbacki. Analogicznie, gdy stan zmieni się na rejected, zostaną wywołane wszystkie callbacki dla tego stanu. Dodatkowo, obiekt ten może pozwalać rejestrować callbacki wywoływane bez względu na stan końcowy.

Z racji, że obiekt Deferred posiada metody sterujące jego stanem, nie jest wskazane jego zwracanie „na zewnątrz”. Dlatego zwracany jest często obiekt Promise, który nie pozwala zmieniać stanu, pozwala tylko rejestrować callbacki.

Wracając do jQuery, callback done zostanie wywołany, gdy animacja zakończy się sukcesem, fail, gdy animacja się nie powiedzie, a always – jak nazwa wskazuje – w obydwu przypadkach.

Kiedy można mówić o porażce w przypadku animacji? Gdy ta zostanie przerwana, np. poprzez wywołanie stop().

Callbacki te zostaną wywołane dla każdego animowanego elementu z osobna, czyli identycznie jak callback complete.

step

Funkcja kroku jest wywoływana najczęściej ze wszystkich omawianych callbacków, dlatego nie powinno się w nich wykonywać skomplikowanych czynności, bo to wpłynie na płynność animacji. Wywołanie następuje co kolejny „krok animacji”, przed zmianą każdej animowanej własności dla każdego animowanego elementu. Czyli, jeśli animujemy 2 własności (np. width i height) na 3 elementach, to funkcja zostanie wywołana 6 razy dla pojedynczego kroku animacji.

Częstotliwość kroku zależy od wewnętrznego zegara animacji.

JS Bin

Callback jest wywoływany z dwoma parametrami. Pierwszy to wartość liczbowa, która została obliczona dla bieżącego kroku animacji. Drugi to obiekt zawierający więcej szczegółów na temat trwającej animacji, takich jak animowany element, animowana własność, obliczona wartość, procent wykonania animacji, jednostka wielkości (np. px, %, pt) oraz większość parametrów przekazanych do wywołania animate. Dzięki drugiemu parametrowi mamy okazję zmienić obliczoną wartość na coś innego, jak w poniższym przykładzie, który ustawia wartości równe najbliższej ćwiartce trwania animacji.

JS Bin

progress

Jak wyżej napisałem, step wywoływana jest co krok animacji, przed zmianą wartości animowanych własności. Z kolei progress będzie wywoływany po każdym kroku. W odróżnieniu od step, progress wywoływany jest raz dla każdego animowanego elementu, a nie dla każdej animowanej właściwości. Czyli przy scenariuszu animowania 2 właściwości na trzech elementach, progress zostanie wywołany co krok 3 razy.

1 callback, gdy wszystkie animacje się zakończą?

Wszystkie powyższe callbacki dotyczą każdego animowanego elementu. A co jeśli chcielibyśmy się dowiedzieć, kiedy animacja skończy animować wszystkie elementy? Do czasu wprowadzenia modelu Promise do jQuery, trzeba było radzić sobie samemu z tym problemem. Teraz wystarczy wywołać metodę promise po wywołaniu animate.

Kod: Zaznacz cały
$("#raz, #dwa, #trzy").animate({
    width: 500
}).promise().done(function () {
    console.log("Koniec animacji. Sukces.");
}).fail(function () {
    console.log("Koniec animacji. Przerwana");
}).always(function () {
    console.log("Koniec animacji");
});

Kolejka animacji

Jest to dość sprytny mechanizm wbudowany w jQuery. Jak już wiemy, działanie animacji jest rozłożone w czasie, wywołanie funkcji animate nie jest blokujące. Co się zatem stanie, gdy animate zostanie wywołane kilka razy?

Kod: Zaznacz cały
$("#animuj-mnie").animate({
    width: 500
}).animate({
    height: 500
}).animate({
    width: 100
}).animate({
    height: 100
});

JS Bin

Otóż wszystkie 4 wywołania trafiają do kolejki animacji i tylko jedna animacja rozpoczyna pracę, pozostałe czekają na zakończenie poprzedniej.

Taki schemat działania animacji jest bardzo wygodny, szczególnie jeśli mamy zamiar definiować całe sekwencje animacji. Bez tego, gdybyśmy chcieli uzyskać ten sam efekt, konieczne byłoby użycie callbacków, czego czytelność pozostawia trochę do życzenia.

Kod: Zaznacz cały
$("#animuj-mnie").animate({
    width: 500
}, function () {
    $(this).animate({
        height: 300
    }, function () {
        $(this).animate({
            width: 100
        }, function () {
            $(this).animate({
                height: 100
            });
        });
    });
});

Domyślnie wszystkie animacje są kolejkowane i trafiają do kolejki o nazwie „fx”. Możemy jednak wpłynąć na domyślne zachowanie i wyłączyć kolejkowanie dla danego wywołania animate.

Kod: Zaznacz cały
$("#animuj-mnie").animate({
    width: 500
}, {
    queue: false
}).animate({
    height: 500
}, {
    queue: false
});

lub można ustalić własną kolejkę dla animacji.

Kod: Zaznacz cały
$("#animuj-mnie").animate({
    width: 500
}, {
    queue: "animacje"
}).animate({
    height: 500
}, {
    queue: "animacje"
});

Do większości zastosowań wystarczy domyślna kolejka „fx”.

Modyfikowanie kolejki

Kilka metod obiektu jQuery pozwala wpływać na kształt i działanie kolejki. queue pozwala umieścić na końcu kolejki dowolną funkcję. Przykładowo, jeśli po wykonaniu animacji, chcemy zmienić kolor tła obiektu, możemy albo skorzystać z callbacka complete albo właśnie z queue.

Kod: Zaznacz cały
$("#test").animate({
    width: 300
}).queue(function (next) {
    $(this).css("background-color", "green");
    next();
});
Zakolejkowana za pomocą queue funkcja powinna po wykonaniu swojej pracy wywołać $(this).dequeue() lub next() (nazwa zależna od nazwy parametru jaką nadamy), żeby poinformować jQuery, że można kontynuować z kolejnymi zadaniami z kolejki. W przeciwnym wypadku dalsze animowanie elementu będzie niemożliwe.

Obydwa sposoby – queue i complete – na pozór działają identycznie, ale diabeł tkwi w szczególach. Po pierwsze, queue kolejkuje zadania, dlatego można je w każdym momencie usunąć. Czynności zdefiniowanych w callbacku complete nie anulujemy już tak łatwo.

Za pomocą dequeue uruchomimy kolejne zadanie z kolejki bez względu na to, czy w danym momencie trwa inna animacja na danym elemencie. Najczęściej użyjemy jej wewnątrz funkcji zakolejkowanych przez queue.

Wywołując delay opóźnimy wykonanie kolejnej animacji z kolejki o podaną ilość milisekund.

Kod: Zaznacz cały
// najpierw zmieni się szerokość, a po 10 sekundach czekania zmieni się wysokość
$("#test").animate({ width: 300 }).delay(10000).animate({ height: 300 });

Jeśli zajdzie konieczność usunięcia wszystkich zakolejkowanych zadań, zrobimy to za pomocą clearQueue.

Zatrzymywanie animacji

jQuery pozwala zatrzymać animację poprzez funkcję stop.

Funkcja wywołana bez parametrów, kończy bieżącą animację, callback complete tej animacji nie zostanie wywołany. Jeśli dla danego elementu zaplanowano więcej animacji, następna w kolejce zostanie uruchomiona.

JS Bin

(proszę zauważyć, że animacja wysokości elementu rozpocznie się po zatrzymaniu animacji szerokości).

Jeśli do funkcji przekażemy true jako pierwszy parametr, oprócz zatrzymania bieżącej animacji, zostanie też wyczyszczona kolejka animacji.

JS Bin

(w tym przypadku, zatrzymanie animacji usunie też animację wysokości elementu).

A jeśli dodamy do parametrów jeszcze jedną wartość true, szerokość elementu przeskoczy do planowanej wartości końcowej, zaś callback complete zostanie wywołany. Animacja wysokości jednak nie nastąpi z powodu true w pierwszym parametrze.

JS Bin

Wraz z wydaniem jQuery 1.9 pojawiła się nowa metoda o nazwie finish, która działa bardzo podobnie do stop. Też zatrzymuje bieżącą animację, czyści kolejkę animacji oraz ustawia końcową wartość właściwościom, których animacje były w kolejce. Callbacki complete wszystkich zakolejkowanych animacji zostaną wywołane.

JS Bin

Gotowce

jQuery oferuje mały zestaw gotowych animacji, służą jednemu celowi – pokazaniu bądź ukryciu elementu. Można te funkcje traktować w zasadzie jako otoczki wokół animate + callback ustawiający display: none po zakończeniu animacji. Są to:

  • fadeIn, fadeOut, fadeToggle, które pokazują lub ukrywają element zwiększając bądź zmniejszając opacity.
    Kod: Zaznacz cały
    $("#test").fadeOut().fadeIn();
  • slideDown, slideUp, slideToggle, które pokazują lub ukrywają element zwiększając bądź zmniejszając wysokość elementu.
    Kod: Zaznacz cały
    $("#test").slideUp().slideDown();
  • show, hide, toggle, które pokazują lub ukrywają element poprzez równoczesną zmianę wysokości, szerokości i opacity elementu.
    Kod: Zaznacz cały
    $("#test").hide("slow").show("fast");
O ile gotowce fade* i slide* można wywołać beż żadnych parametrów, to show, hide i toggle, żeby zachowywały się jak funkcje animacyjne, wymagają co najmniej 1 parametru. W przeciwnym wypadku funkcja pokaże lub ukryje element natychmiast, bez efektu przejścia.

JS Bin

Podsumowanie

O animacjach w jQuery można długo pisać. Powyższy tekst stanowi tylko proste wprowadzenie do tego modułu. Zachęcam do dyskusji na forum na temat bardziej skomplikowanych przypadków stosowania animacji.

Masz pytania lub wątpliwości? Odwiedź nasze forum dyskusyjne.

Rafał Kukawski

Programista, webmaster. Szczególnie upodobał sobie JavaScript i technologie klienckie, choć strona serwera i bazy danych nie stanowią tajemnicy. Tworzy też aplikacje na urządzenia mobilne. kukawski.pl.


Komentarze


HTML CSS JavaScript PHP bazy danych MySQL Flash grafika framework hosting domeny pozycjonowanie wordpress Facebook