Tutorial VueJS 3: transizioni e animazioni con Transition
verificato il 2 Settembre 2026 · 5 min
<Transition> anima un singolo elemento quando compare e quando sparisce, <TransitionGroup> anima una lista. Vue applica classi CSS, il vostro foglio di stile decide l’effetto. Attenzione: in Vue 3 le classi di partenza sono -enter-from e -leave-from, non -enter e -leave come in Vue 2.
Un elemento che compare di colpo produce un effetto di scatto. Vue offre due componenti integrati, <Transition> e <TransitionGroup>, che applicano classi CSS al momento giusto per animare le entrate e le uscite. Nessuna libreria da installare.
Il principio
Avvolgete in <Transition> un elemento la cui visualizzazione dipende da una condizione. Vue non lo anima da sé: aggiunge e toglie classi, ed è il vostro CSS a decidere l’effetto.
Sei classi coprono l’intero ciclo.
/* entrata */
.v-enter-from /* stato di partenza, applicato appena prima dell’inserimento */
.v-enter-active /* per tutta l’entrata: è qui che va transition */
.v-enter-to /* stato di arrivo */
/* uscita */
.v-leave-from /* stato di partenza dell’uscita */
.v-leave-active /* per tutta l’uscita */
.v-leave-to /* stato finale, appena prima della rimozione dal DOM */Il prefisso v- è quello di una transizione senza nome. Con name="fade", le classi diventano fade-enter-from, fade-enter-active, e così via.
In Vue 2 le classi di partenza si chiamavano .fade-enter e .fade-leave, senza suffisso. Vue 3 le ha rinominate in -enter-from e -leave-from. Un esempio copiato da un articolo vecchio non produrrà quindi alcuna animazione in entrata, senza il minimo messaggio di errore. Se la vostra transizione non fa nulla, verificate prima questo punto.
Animare la disponibilità
In ProductDisplay.vue, il messaggio di disponibilità passa da un paragrafo all’altro a seconda della variante sotto il puntatore. Avvolgeteli:
<Transition name="fade" mode="out-in">
<p v-if="inStock" key="in">En stock</p>
<p v-else key="out">En rupture</p>
</Transition>Poi descrivete l’effetto nel foglio di stile, come nel capitolo sulle classi e gli stili:
.fade-enter-from,
.fade-leave-to {
opacity: 0;
transform: translateY(-10px);
}
.fade-enter-active,
.fade-leave-active {
transition: opacity .3s ease, transform .3s ease;
}Passate sopra ai pallini: il messaggio sfuma invece di scattare.
mode="out-in" attende che l’elemento vecchio sia uscito prima di inserire quello nuovo. Senza, i due paragrafi coesistono per una frazione di secondo e si sovrappongono.
Che cosa accetta Transition
Un solo elemento alla volta. È il vincolo principale: <Transition> anima un unico figlio, non una lista.
Si attiva in tre situazioni: un v-if, un v-show, oppure un cambio di componente via <component :is>. Per forzare una transizione fra due elementi dello stesso tipo, dategli key diverse, come sopra.
Animare una lista
Per una lista serve <TransitionGroup>. Due differenze: accetta più figli e rende esso stesso un elemento contenitore se glielo chiedete con tag.
In ReviewList.vue, sostituite il <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>Ogni figlio ha bisogno di una key unica e stabile. L’indice qui non va bene: cambia a ogni inserimento, e Vue non saprebbe più quale elemento è nuovo. Diamo un identificatore a ogni recensione al momento dell’aggiunta:
<script setup>
function addReview(review) {
reviews.value.push({ ...review, id: crypto.randomUUID() })
}
</script>crypto.randomUUID() è disponibile in tutti i browser aggiornati, sulle pagine servite in HTTPS o da localhost.
Il CSS aggiunge una classe in più, -move, che anima lo spostamento degli elementi rimasti quando un vicino sparisce:
.liste-enter-from,
.liste-leave-to {
opacity: 0;
transform: translateX(24px);
}
.liste-enter-active,
.liste-leave-active,
.liste-move {
transition: all .3s ease;
}Inviate più recensioni: ognuna entra scorrendo, e le altre si riorganizzano dolcemente.
Perché -move funzioni alla rimozione, l’elemento che esce deve essere tolto dal flusso, altrimenti gli altri si muovono solo alla fine della sua animazione. Aggiungete position: absolute alla classe -leave-active quando i vostri elementi sono eliminabili.
Animare alla prima visualizzazione
Per impostazione predefinita, nulla viene animato al rendering iniziale. L’attributo appear cambia le cose:
<Transition name="fade" appear>
<p>Visible dès le chargement, en fondu</p>
</Transition>Le animazioni CSS e gli hook
transition non è l’unica opzione: funziona anche una animation CSS, applicata sulla classe -enter-active.
Per pilotare una libreria di animazione in JavaScript, <Transition> emette eventi a ogni tappa:
<Transition
:css="false"
@before-enter="avantEntree"
@enter="entree"
@after-enter="apresEntree"
@leave="sortie"
>
<p v-if="visible">Contenu</p>
</Transition>Con :css="false", Vue smette di gestire le classi e vi lascia il comando. Le funzioni enter e leave ricevono allora l’elemento e una callback done da chiamare quando l’animazione è finita:
function entree(el, done) {
// animazione con la libreria che preferite
done()
}Il movimento non è sempre desiderabile
Alcune persone disattivano le animazioni a livello di sistema, in particolare per evitare la nausea legata al movimento. Rispettate questa impostazione:
@media (prefers-reduced-motion: reduce) {
.fade-enter-active,
.fade-leave-active,
.liste-enter-active,
.liste-leave-active,
.liste-move {
transition: none;
}
}L’interfaccia resta funzionante, sparisce solo l’animazione.
È la fine del tutorial
La vostra applicazione mostra un prodotto e le sue varianti, gestisce un carrello, valida un modulo e anima i suoi cambi di stato. Avete coperto la reattività, le direttive, i componenti, le props, gli eventi e le transizioni: quanto basta per leggere e scrivere Vue tutti i giorni.
Per il seguito, due direzioni. La condivisione dello stato fra componenti lontani con Pinia, quando far risalire gli eventi diventa faticoso. E il routing con Vue Router, appena l’applicazione ha più pagine.
<Transition> e <TransitionGroup> sono componenti integrati: si scrivono esattamente allo stesso modo. Cambiano posto solo le funzioni degli hook JavaScript, che finiscono nell’opzione methods.
key legata alla variante selezionata.Errori frequenti
.fade-enter e .fade-leave sono state rinominate in -enter-from e -leave-from. Non si anima nulla e non compare alcun errore.global: { stubs: { 'transition-group': false } } per osservare il rendering reale.