Kurs Vue.js · Moduł 13: Przejścia i animacje
JavaScript Animation Hooks
W tej lekcji7
Klasy CSS to "autopilot" animacji - działa świetnie dla prostych przejść. Ale czasem potrzebujesz pełnej kontroli nad animacjami - np. dynamicznie obliczanych wartości, animacji zależnych od danych, albo integracji z bibliotekami JS. W takich przypadkach Vue oferuje JavaScript animation hooks - jak ręczne sterowanie rakietą zamiast automatycznego lotu.
Dostępne hooki
<Transition> emituje zdarzenia na każdym etapie animacji. Możesz na nie nasłuchiwać:
1<Transition
2 :css="false"
3 @before-enter="onBeforeEnter"
4 @enter="onEnter"
5 @after-enter="onAfterEnter"
6 @enter-cancelled="onEnterCancelled"
7 @before-leave="onBeforeLeave"
8 @leave="onLeave"
9 @after-leave="onAfterLeave"
10 @leave-cancelled="onLeaveCancelled"
11>
12 <div v-if="show">...</div>
13</Transition>Hooki wejścia (enter) - kolejność wywołania
@before-enter(el)- wywoływany zanim element zostanie wstawiony do DOM. Tutaj ustawiasz stan początkowy animacji (np.opacity: 0,scale: 0.5).@enter(el, done)- wywoływany w następnej klatce po wstawieniu elementu. Tu uruchamiasz właściwą animację. Musisz wywołaćdone()gdy animacja się zakończy!@after-enter(el)- wywoływany po zakończeniu animacji (podone()). Tutaj sprzątasz po animacji (usuwasz inline styles itp.).@enter-cancelled(el)- wywoływany gdy animacja wejścia zostanie przerwana (np. użytkownik szybko toggle'uje element).
Hooki wyjścia (leave) - analogiczna kolejność
@before-leave(el)- stan początkowy wyjścia, element jest jeszcze widoczny@leave(el, done)- animacja wyjścia, musisz wywołaćdone()!@after-leave(el)- cleanup po wyjściu@leave-cancelled(el)- przerwanie animacji wyjścia (tylko zv-show)
Atrybut :css="false"
Gdy używasz wyłącznie hooków JS, dodaj :css="false" aby Vue nie próbowało stosować klas CSS ani nasłuchiwać na transitionend/animationend:
1<Transition :css="false" @enter="onEnter" @leave="onLeave">
2 <div v-if="show">Panel kontrolny</div>
3</Transition>Bez tego atrybutu Vue będzie czekało zarówno na callback done(), jak i na zdarzenie CSS transition - co może powodować nieprzewidywalne zachowanie.
Callback done() - kluczowy element
done() jest obowiązkowy w hookach @enter i @leave. Informuje Vue, że animacja się zakończyła i można przejść do następnego kroku:
1function onBeforeEnter(el) {
2 // Stan początkowy - element niewidoczny
3 el.style.opacity = 0
4 el.style.transform = 'translateY(20px)'
5}
6
7function onEnter(el, done) {
8 // Wymuś reflow, aby przeglądarka zarejestrowała stan początkowy
9 el.offsetHeight
10
11 // Uruchom animację
12 el.style.transition = 'all 0.5s ease'
13 el.style.opacity = 1
14 el.style.transform = 'translateY(0)'
15
16 // Powiadom Vue gdy animacja się zakończy
17 el.addEventListener('transitionend', done, { once: true })
18}
19
20function onAfterEnter(el) {
21 // Cleanup - usuń inline transition
22 el.style.transition = ''
23}Bez wywołania done() Vue nie wie kiedy animacja się zakończyła - w przypadku @leave element nigdy nie zostanie usunięty z DOM.
Praktyczny przykład - animacja zależna od danych
Hooki JS pozwalają na dynamiczne wartości, czego CSS classes nie umożliwiają:
1function onEnter(el, done) {
2 // Dynamiczny kierunek animacji na podstawie danych
3 const direction = el.dataset.direction || 'left'
4 const offset = direction === 'left' ? '-100px' : '100px'
5
6 el.style.opacity = 0
7 el.style.transform = `translateX(${offset})`
8 el.offsetHeight // reflow
9
10 el.style.transition = 'all 0.4s ease-out'
11 el.style.opacity = 1
12 el.style.transform = 'translateX(0)'
13
14 el.addEventListener('transitionend', done, { once: true })
15}Kiedy używać hooków JS zamiast CSS?
| Użyj CSS klas | Użyj JS hooków |
|---|---|
| Proste fade, slide | Dynamiczne wartości animacji |
| Stałe czasy trwania | Czasy zależne od danych |
| Typowe przejścia | Integracja z GSAP, Anime.js |
| Większość przypadków | Złożone sekwencje animacji |
Kod do tej lekcji: App.vue
1<script setup>
2import { ref } from 'vue'
3
4const showAlert = ref(false)
5
6function onBeforeEnter(el) {
7 el.style.opacity = 0
8 el.style.transform = 'scale(0.5)'
9}
10
11function onEnter(el, done) {
12 // Animacja wejścia bez CSS
13 el.offsetHeight // wymuszenie reflow
14 el.style.transition = 'all 0.6s ease'
15 el.style.opacity = 1
16 el.style.transform = 'scale(1)'
17 el.addEventListener('transitionend', done, { once: true })
18}
19
20function onLeave(el, done) {
21 el.style.transition = 'all 0.4s ease'
22 el.style.opacity = 0
23 el.style.transform = 'scale(0.5) rotate(10deg)'
24 el.addEventListener('transitionend', done, { once: true })
25}
26</script>
27
28<template>
29 <div class="nova-lab">
30 <h1>JavaScript Animation Hooks</h1>
31
32 <button @click="showAlert = !showAlert" class="btn">
33 {{ showAlert ? 'Zamknij alert' : 'Pokaż alert' }}
34 </button>
35
36 <Transition
37 :css="false"
38 @before-enter="onBeforeEnter"
39 @enter="onEnter"
40 @leave="onLeave"
41 >
42 <div v-if="showAlert" class="alert">
43 UWAGA: Wykryto anomalię grawitacyjną w sektorze 7!
44 </div>
45 </Transition>
46 </div>
47</template>
48
49<style scoped>
50.nova-lab {
51 background: #0a0e27;
52 color: #00ff88;
53 min-height: 100vh;
54 padding: 20px;
55 font-family: monospace;
56}
57h1 { color: #00ff88; }
58.btn {
59 background: #e74c3c;
60 color: white;
61 border: none;
62 padding: 10px 20px;
63 border-radius: 8px;
64 cursor: pointer;
65 margin: 15px 0;
66}
67.alert {
68 background: rgba(231, 76, 60, 0.2);
69 border: 2px solid #e74c3c;
70 color: #e74c3c;
71 padding: 20px;
72 border-radius: 12px;
73 font-size: 16px;
74}
75</style>Widzisz błąd w tej lekcji?
Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. Który JavaScript hook jest wywoływany gdy element wchodzi do DOM?
2. Co należy wywołać na końcu hooka @enter aby poinformować Vue o zakończeniu animacji?
Zadania praktyczne w grze
- Układanie w pionie
Ułóż hooki JavaScript Transition w kolejności wywołania (wejście):
- Edytor kodu
Zaimplementuj @enter i @leave z użyciem el.style i done() callback.
- Klikanie w kolejności
Ułóż kod hooka @enter w prawidłowej kolejności:
- Układanie w poziomie
Ułóż składnię Transition wyłączającą klasy CSS:
- Edytor kodu
Użyj :css='false' i hooków JS do animacji opacity i scale.
- Układanie w poziomie
Ułóż deklarację hooka @leave w template: