Capítulo 11 de 11

Tutorial Vue 3: transições e animações com Transition

verificado a 2 Setembro 2026 · 5 min

Resposta rápida

<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.

No fim deste capítulo, saberá animar o aparecimento, o desaparecimento e a deslocação de elementos, sem biblioteca.

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.

css
/* 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.

A armadilha do código encontrado na web

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:

src/components/ProductDisplay.vue
<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:

src/assets/boutique.css
.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>:

src/components/ReviewList.vue
<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:

src/components/ProductDisplay.vue
<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:

src/assets/boutique.css
.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.

Saída e deslocação

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:

html
<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:

html
<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:

javascript
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:

src/assets/boutique.css
@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.

Na Options API

<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.

ExercícioAcrescente uma transição na imagem do produto para que se esbata na mudança de variante. Vai precisar de uma key ligada à variante selecionada.

Erros frequentes

Usar as classes do Vue 2 .fade-enter e .fade-leave foram renomeadas para -enter-from e -leave-from. Nada se anima e nenhum erro aparece.
Esquecer mode="out-in" Sem ele, o elemento que entra e o que sai coexistem uma fração de segundo e sobrepõem-se.
Usar o índice como chave num TransitionGroup O Vue deixa de distinguir o elemento novo dos outros e anima a entrada errada.
Testar um componente animado com o Vue Test Utils As transições são substituídas por stubs por omissão. Passe global: { stubs: { 'transition-group': false } } para observar o rendering real.
Newsletter

Os novos testes, tutoriais e projetos, por e-mail.

Testes reproduzíveis, código versionado, resultados datados. Nunca spam.