Kurs Vue 3: przejścia i animacje z Transition i TransitionGroup
zweryfikowano 2 września 2026 · 5 min
<Transition> animuje pojedynczy element przy pojawieniu się i zniknięciu, <TransitionGroup> animuje listę. Vue nakłada klasy CSS, a o efekcie decyduje twój arkusz stylów. Uwaga: w Vue 3 klasy początkowe to -enter-from i -leave-from, a nie -enter i -leave jak w Vue 2.
Element, który pojawia się od razu, sprawia wrażenie przeskoku. Vue dostarcza dwa wbudowane komponenty, <Transition> i <TransitionGroup>, które w odpowiednim momencie nakładają klasy CSS, aby animować pojawianie się i znikanie. Żadnej biblioteki do instalowania.
Zasada działania
Owiń w <Transition> element, którego wyświetlanie zależy od warunku. Vue samo go nie animuje: dodaje i usuwa klasy, a o efekcie decyduje twój CSS.
Sześć klas obejmuje pełny cykl.
/* wejście */
.v-enter-from /* stan początkowy, nakładany tuż przed wstawieniem */
.v-enter-active /* przez całe wejście: tutaj trafia transition */
.v-enter-to /* stan docelowy */
/* wyjście */
.v-leave-from /* stan początkowy wyjścia */
.v-leave-active /* przez całe wyjście */
.v-leave-to /* stan końcowy, tuż przed usunięciem z DOM */Przedrostek v- należy do przejścia bez nazwy. Przy name="fade" klasy stają się fade-enter-from, fade-enter-active i tak dalej.
W Vue 2 klasy początkowe nazywały się .fade-enter i .fade-leave, bez przyrostka. Vue 3 zmieniło ich nazwy na -enter-from i -leave-from. Przykład skopiowany ze starego artykułu nie wywoła więc żadnej animacji przy wejściu, bez najmniejszego komunikatu o błędzie. Jeśli twoje przejście nic nie robi, sprawdź najpierw ten punkt.
Animowanie dostępności
W ProductDisplay.vue komunikat o stanie magazynu przełącza się między dwoma akapitami zależnie od wariantu pod kursorem. Owiń je:
<Transition name="fade" mode="out-in">
<p v-if="inStock" key="in">En stock</p>
<p v-else key="out">En rupture</p>
</Transition>Następnie opisz efekt w arkuszu stylów, tak jak w rozdziale o klasach i stylach:
.fade-enter-from,
.fade-leave-to {
opacity: 0;
transform: translateY(-10px);
}
.fade-enter-active,
.fade-leave-active {
transition: opacity .3s ease, transform .3s ease;
}Najedź na kolorowe kropki: komunikat przenika zamiast przeskakiwać.
mode="out-in" czeka, aż stary element zniknie, zanim wstawi nowy. Bez niego oba akapity współistnieją przez ułamek sekundy i nakładają się na siebie.
Co przyjmuje Transition
Tylko jeden element naraz. To główne ograniczenie: <Transition> animuje pojedyncze dziecko, a nie listę.
Uruchamia się w trzech sytuacjach: przy v-if, przy v-show albo przy zmianie komponentu przez <component :is>. Aby wymusić przejście między dwoma elementami tego samego typu, nadaj im różne key, jak powyżej.
Animowanie listy
Do listy potrzebny jest <TransitionGroup>. Dwie różnice: przyjmuje wiele dzieci i sam renderuje element kontenera, jeśli poprosisz o to atrybutem tag.
W ReviewList.vue zastąp <ul>:
<template>
<div class="review-container">
<h3>Avis</h3>
<TransitionGroup name="liste" tag="ul">
<li v-for="review in reviews" :key="review.id">
{{ review.name }} a mis {{ review.rating }} étoiles
<br>
« {{ review.review }} »
</li>
</TransitionGroup>
</div>
</template>Każde dziecko potrzebuje unikalnego i stabilnego key. Indeks tutaj nie wystarczy: zmienia się przy każdym wstawieniu, a Vue nie wiedziałoby już, który element jest nowy. Nadajmy każdej opinii identyfikator w chwili dodania:
<script setup>
function addReview(review) {
reviews.value.push({ ...review, id: crypto.randomUUID() })
}
</script>crypto.randomUUID() jest dostępne we wszystkich aktualnych przeglądarkach, na stronach serwowanych po HTTPS lub z localhost.
CSS zyskuje jeszcze jedną klasę, -move, która animuje przesuwanie pozostałych elementów, gdy sąsiad znika:
.liste-enter-from,
.liste-leave-to {
opacity: 0;
transform: translateX(24px);
}
.liste-enter-active,
.liste-leave-active,
.liste-move {
transition: all .3s ease;
}Dodaj kilka opinii: każda wjeżdża, a pozostałe płynnie się porządkują.
Żeby -move działało przy usuwaniu, znikający element musi zostać wyjęty z układu, inaczej pozostałe ruszą się dopiero po zakończeniu jego animacji. Dodaj position: absolute do klasy -leave-active, gdy twoje elementy można usuwać.
Animowanie przy pierwszym wyświetleniu
Domyślnie przy pierwszym renderowaniu nic nie jest animowane. Zmienia to atrybut appear:
<Transition name="fade" appear>
<p>Visible dès le chargement, en fondu</p>
</Transition>Animacje CSS i haki
transition to nie jedyna opcja: działa też animacja CSS animation, nałożona na klasę -enter-active.
Aby sterować biblioteką animacji w JavaScripcie, <Transition> emituje zdarzenia na każdym etapie:
<Transition
:css="false"
@before-enter="avantEntree"
@enter="entree"
@after-enter="apresEntree"
@leave="sortie"
>
<p v-if="visible">Contenu</p>
</Transition>Przy :css="false" Vue przestaje zarządzać klasami i oddaje ci stery. Funkcje enter i leave otrzymują wtedy element oraz wywołanie zwrotne done, które trzeba wywołać po zakończeniu animacji:
function entree(el, done) {
// animacja przy użyciu wybranej biblioteki
done()
}Ruch nie zawsze jest pożądany
Część osób wyłącza animacje na poziomie systemu, zwłaszcza po to, by uniknąć mdłości wywołanych ruchem. Uszanuj to ustawienie:
@media (prefers-reduced-motion: reduce) {
.fade-enter-active,
.fade-leave-active,
.liste-enter-active,
.liste-leave-active,
.liste-move {
transition: none;
}
}Interfejs pozostaje sprawny, znika tylko animacja.
To koniec kursu
Twoja aplikacja pokazuje produkt i jego warianty, obsługuje koszyk, waliduje formularz i animuje zmiany stanu. Przeszedłeś reaktywność, dyrektywy, komponenty, propsy, zdarzenia i przejścia: tyle, by na co dzień czytać i pisać w Vue.
Dalej dwie drogi. Współdzielenie stanu między odległymi komponentami z Pinią, gdy przekazywanie zdarzeń w górę staje się uciążliwe. Oraz routing z Vue Routerem, gdy tylko aplikacja ma kilka stron.
<Transition> i <TransitionGroup> są komponentami wbudowanymi: zapisuje się je dokładnie tak samo. Zmieniają miejsce tylko funkcje haków JavaScript, które trafiają do opcji methods.
key powiązany z wybranym wariantem.Częste błędy
.fade-enter i .fade-leave zostały przemianowane na -enter-from i -leave-from. Nic się nie animuje i nie pojawia się żaden błąd.global: { stubs: { 'transition-group': false } }, aby zobaczyć prawdziwy render.