Tutorial Vue 3: transições e animações com Transition
verificado a 2 Setembro 2026 · 5 min
<Transition> anima um elemento único quando aparece e quando desaparece, <TransitionGroup> anima uma lista. O Vue aplica classes CSS, a sua folha de estilos decide o efeito. Atenção: no Vue 3, as classes de partida são -enter-from e -leave-from, não -enter e -leave como no Vue 2.
Um elemento que aparece de repente produz um efeito de salto. O Vue traz dois componentes integrados, <Transition> e <TransitionGroup>, que aplicam classes CSS no momento certo para animar as entradas e as saídas. Nenhuma biblioteca para instalar.
O princípio
Envolva em <Transition> um elemento cuja exibição depende de uma condição. O Vue não o anima ele próprio: acrescenta e retira classes, e é o seu CSS que decide o efeito.
Seis classes cobrem o ciclo completo.
/* entrada */
.v-enter-from /* estado de partida, aplicado mesmo antes da inserção */
.v-enter-active /* durante toda a entrada: é aqui que vai transition */
.v-enter-to /* estado de chegada */
/* saída */
.v-leave-from /* estado de partida da saída */
.v-leave-active /* durante toda a saída */
.v-leave-to /* estado final, mesmo antes da remoção do DOM */O prefixo v- é o de uma transição sem nome. Com name="fade", as classes passam a ser fade-enter-from, fade-enter-active, e assim por diante.
No Vue 2, as classes de partida chamavam-se .fade-enter e .fade-leave, sem sufixo. O Vue 3 renomeou-as para -enter-from e -leave-from. Um exemplo copiado de um artigo antigo não produzirá, portanto, qualquer animação à entrada, sem a mínima mensagem de erro. Se a sua transição não faz nada, verifique primeiro este ponto.
Animar a disponibilidade
Em ProductDisplay.vue, a mensagem de stock alterna entre dois parágrafos consoante a variante sobrevoada. Envolva-os:
<Transition name="fade" mode="out-in">
<p v-if="inStock" key="in">En stock</p>
<p v-else key="out">En rupture</p>
</Transition>Depois descreva o efeito na folha de estilos, como no capítulo sobre as classes e os estilos:
.fade-enter-from,
.fade-leave-to {
opacity: 0;
transform: translateY(-10px);
}
.fade-enter-active,
.fade-leave-active {
transition: opacity .3s ease, transform .3s ease;
}Passe o rato pelos círculos de cor: a mensagem esbate-se em vez de saltar.
mode="out-in" espera que o elemento antigo tenha saído antes de inserir o novo. Sem ele, os dois parágrafos coexistem uma fração de segundo e sobrepõem-se.
O que o Transition aceita
Um único elemento de cada vez. É a principal restrição: <Transition> anima um filho único, não uma lista.
É acionado em três situações: um v-if, um v-show, ou uma mudança de componente através de <component :is>. Para forçar uma transição entre dois elementos do mesmo tipo, dê-lhes key diferentes, como acima.
Animar uma lista
Para uma lista é preciso <TransitionGroup>. Duas diferenças: aceita vários filhos e rende ele próprio um elemento contentor se lho pedir com tag.
Em ReviewList.vue, substitua o <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>Cada filho precisa de uma key única e estável. O índice não serve aqui: muda a cada inserção, e o Vue deixaria de saber qual é o elemento novo. Vamos dar um identificador a cada avaliação no momento em que é adicionada:
<script setup>
function addReview(review) {
reviews.value.push({ ...review, id: crypto.randomUUID() })
}
</script>crypto.randomUUID() está disponível em todos os navegadores atualizados, em páginas servidas por HTTPS ou a partir de localhost.
O CSS acrescenta mais uma classe, -move, que anima a deslocação dos elementos restantes quando um vizinho desaparece:
.liste-enter-from,
.liste-leave-to {
opacity: 0;
transform: translateX(24px);
}
.liste-enter-active,
.liste-leave-active,
.liste-move {
transition: all .3s ease;
}Envie várias avaliações: cada uma entra a deslizar, e as outras reorganizam-se suavemente.
Para que -move funcione na remoção, o elemento que sai tem de ser retirado do fluxo, senão os outros só se movem no fim da sua animação. Acrescente position: absolute à classe -leave-active quando os seus elementos puderem ser eliminados.
Animar na primeira exibição
Por omissão, nada é animado no rendering inicial. O atributo appear muda isso:
<Transition name="fade" appear>
<p>Visible dès le chargement, en fondu</p>
</Transition>As animações CSS e os hooks
transition não é a única opção: uma animation CSS também funciona, aplicada sobre a classe -enter-active.
Para pilotar uma biblioteca de animação em JavaScript, <Transition> emite eventos em cada etapa:
<Transition
:css="false"
@before-enter="avantEntree"
@enter="entree"
@after-enter="apresEntree"
@leave="sortie"
>
<p v-if="visible">Contenu</p>
</Transition>Com :css="false", o Vue deixa de gerir as classes e passa-lhe o comando. As funções enter e leave recebem então o elemento e um callback done a chamar quando a animação termina:
function entree(el, done) {
// animação com a biblioteca à sua escolha
done()
}O movimento nem sempre é desejável
Algumas pessoas desativam as animações ao nível do sistema, nomeadamente para evitar as náuseas ligadas ao movimento. Respeite essa definição:
@media (prefers-reduced-motion: reduce) {
.fade-enter-active,
.fade-leave-active,
.liste-enter-active,
.liste-leave-active,
.liste-move {
transition: none;
}
}A interface continua funcional, só a animação desaparece.
É o fim do tutorial
A sua aplicação mostra um produto e as suas variantes, gere um carrinho, valida um formulário e anima as suas mudanças de estado. Cobriu a reatividade, as diretivas, os componentes, as props, os eventos e as transições: o suficiente para ler e escrever Vue no dia a dia.
Para a continuação, duas direções. A partilha de estado entre componentes distantes com Pinia, quando fazer subir os eventos se torna penoso. E o encaminhamento com o Vue Router, assim que a aplicação tem várias páginas.
<Transition> e <TransitionGroup> são componentes integrados: escrevem-se exatamente da mesma maneira. Só as funções dos hooks JavaScript mudam de sítio, para a opção methods.
key ligada à variante selecionada.Erros frequentes
.fade-enter e .fade-leave foram renomeadas para -enter-from e -leave-from. Nada se anima e nenhum erro aparece.global: { stubs: { 'transition-group': false } } para observar o rendering real.