jQuery - animacje
W bardzo wielu przypadkach będziemy chcieli dane elementy strony animować. Możemy to zrobić za pomocą metody animate(properties, time*, ease*, fn*). Najbardziej interesującymi nas parametrami są properties, do których przekazujemy obiekt składający się z właściwości i ich nowych wielkości:
<button type="button" class="button" id="testAnim">Animuj</button>
<div id="testAnimBlock" class="test-block">DIV</div>
$("#testAnim1").on("click", function(){
$(this).animate({
width: "500px",
opacity: 0.4,
fontSize: "3em",
borderWidth: "10px"
}, 1500);
});
Parametr ease określa przebieg animacji.
jQuery posiada wbudowane dwa rodzaje przebiegu animacji: linear i swing.
Aby skorzystać z innych rodzajów, powinniśmy skorzystać z dodatkowych pluginów do jQuery, np. tego:
http://gsgd.co.uk/sandbox/jquery/easing/.
$("#testAnim2").on("click", function(){
$(this).animate({
height:200,
width:400,
opacity: 0.5
},
{
duration: 1000, //czas animacji
ease: "linear", //typ animacji
complete: function() { //funkcja zwrotna
alert("koniec animacji");
}
}
);
});
Po dodaniu powyższej biblioteki z serwera CDN (np. stąd) możemy użyć o wiele więcej typów animacji:
$("#testAnim2").on("click", function(){
$(this).animate({
height:200,
width:400,
opacity: 0.5
},
{
duration: 1000, //czas animacji
easing: "easeOutBounce", //typ animacji
complete: function() { //funkcja zwrotna
alert("koniec animacji");
}
}
);
});
Uproszczony zapis
Powyższy zapis definicji animacji mimo, że czytelny, jest nieco długi. W wielu sytuacjach będziesz chciał zastosować uproszczony zapis:
$(".module1").animate({width: 500});
$(".module2").animate({width: 500}, 1000);
$(".module3").animate({width: 500}, 1000, function() {
console.log("koniec animacji");
});
Poza właściwościami wszystkie atrybuty są opcjonalne, więc możemy ich nie podawać. Jak widzisz, nie musimy nawet przekazywać obiektu z ustawieniami, a tylko podać je w odpowiedniej kolejności.
Inne opcje dla wartości
W powyższych przykładach animowane właściwości ustawiłem na sztywno.
W jQuery można także zastosować wartości relatywne za pomocą zapisów -= lub +=, które
odejmą lub dodadzą odpowiednią wielkość od aktualnej:
$("#testAnim4").on("click", function(){
$(this).animate({
width: "+=" + 50,
height: "+=" + 10,
opacity: "-=" + 0.1,
duration : 2000 //inny sposób deklaracji czasu trwania animacji
});
});
Poprawa animacji
Przyjrzyjmy się teraz pewnej sytuacji.
Mamy blok, po najechaniu na który chcemy płynnie zmienić jego rozmiary w zależności od
tego czy kursor na nim jest czy nie. Po zjechaniu kursorem animacja powinna wrócić do początkowego stanu:
$("#testAnim5").on({
"mouseover" : function() {
$(this).animate({
width: 300
}, 800);
},
"mouseout" : function() {
$(this).animate({
width: 200
}, 800);
}
});
Problem pojawi się wtedy, gdy użytkownik zacznie się pastwić nad naszym elementem szybko najeżdżając i opuszczając go kursorem. Kilka takich ruchów i animacja się zapętla, mimo, że już dawno jesteśmy kursorem w innym miejscu. Spowodowane jest to tym, że nasza animacja nie zdąży się do końca wykonać, a my chcemy odpalić ją ponownie.
Aby temu zapobiec musimy posiłkować się jedną z dwóch technik.
Pierwsza z nich polega na wykorzystaniu metody stop(), która zatrzyma odpaloną animację:
$("#testAnim6").on({
"mouseover" : function() {
$(this).stop().animate({width:300}, 500);
},
"mouseout" : function() {
$(this).stop().animate({width:200}, 500);
}
});
Druga metoda polega na sprawdzaniu czy dany element nie zakończył swojej animacji:
$("#testAnim7").on("click", function(){
if (!$(this).is(":animated")) {
$(this).animate({
width: "+=" + 50,
height: "+=" + 10,
opacity: "-=" + 0.1,
duration : 3000 //inny sposób deklaracji czasu trwania animacji
});
}
});
Zauważ, że w przeciwieństwie do jednego z poprzednich przykładów teraz nawet jak będziesz szybko klikał, to po przerwaniu tego szaleństwa (...) div nie będzie kontynuował swojego rozrostu.
Powyższe dwa sposoby sprawdzają się w innych zastosowaniach. Metoda stop() lepiej sprawdza się w zdarzeniach mouseover i mouseout, natomiast sprawdzanie czy obiekt jest animowany lepiej stosować przy zdarzeniach click
Delay
Metoda delay(time) służy do opóźniania kolejnych czynności w składni łańcuchowej (gdzie kolejne polecenia są łączone kropką):
$(".element")
.hide()
.delay(2000) //czekam 2 sekundy
.slideDown();
Metoda ta ma szczególne zastosowanie gdy chcemy dla przykładu rozwinąć kolejne elementy dodawane do dynamicznej listy.
Wyobraź sobie, że masz listę użytkowników:
const users = [
{ name : "Marcin", surname : "Nowak" },
{ name : "Piotr", surname : "Kowalski" },
{ name : "Grzegorz", surname : "Piotrowski" },
{ name : "Karol", surname : "Karolak" },
{ name : "Michał", surname : "Nowacki" }
]
Chcielibyśmy zrobić pętlę po takiej tablicy, dynamicznie wygenerować dla każdego użytkownika kontener i wrzucić go do listy:
$(".add-button").on("click", function() {
const $userList = $(".user-list");
users.forEach(function(user) {
const html = `<div class="user-cnt">
<strong class="user-name-label">Nazwa użytkownika:</strong>
<span class="user-name">${user.name} ${user.surname}</span>
</div>`;
const $cnt = $(html);
$userList.append($cnt)
});
});
Jak widzisz dodawanie działa, ale nie jest wizualnie dobre dla użytkownika. O wiele lepszym rozwiązaniem będzie rozwijać dodawane elementy:
const $userList = $(".user-list");
$(".add-button").on("click", function() {
users.forEach(function(user) {
const html = `<div class="user-cnt">
<strong class="user-name-label">Nazwa użytkownika:</strong>
<span class="user-name">${user.name} ${user.surname}</span>
</div>`;
const $cnt = $(html).hide();
$userList.append($cnt);
$cnt.slideDown();
});
});
Problem z tym podejściem jest taki, że wszystkie elementy są rozwijane w tym samym momencie. I tutaj właśnie idealnym rozwiązaniem będzie użycie delay(), tak by elementy rozwijały się jeden po drugim:
const $userList = $(".user-list");
$(".add-button").on("click", function() {
users.forEach(function(user, i) {
const html = `<div class="user-cnt">
<strong class="user-name-label">Nazwa użytkownika:</strong>
<span class="user-name">${user.name} ${user.surname}</span>
</div>`;
const $cnt = $(html).hide();
$userList.append($cnt);
$cnt.delay(300*i).slideDown();
});
});