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.
<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>
— wywoływany zanim element zostanie wstawiony do DOM. Tutaj ustawiasz stan początkowy animacji (np. @before-enter(el)
opacity: 0, scale: 0.5).
— wywoływany w następnej klatce po wstawieniu elementu. Tu uruchamiasz właściwą animację. Musisz wywołać @enter(el, done)
gdy animacja się zakończy!done()
— wywoływany po zakończeniu animacji (po @after-enter(el)
done()). Tutaj sprzątasz po animacji (usuwasz inline styles itp.).
— wywoływany gdy animacja wejścia zostanie przerwana (np. użytkownik szybko toggle'uje element).@enter-cancelled(el)
@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 z v-show)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.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.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}| 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 |