Clique aqui para a documentação da v3.x.

Você está navegando a documentação da v2.x e anterior. Para a v3.x, clique aqui.

Transições de Visibilidade e Listas

Visão Geral

Vue disponibiliza uma variedade de maneiras para a aplicação de efeitos de transição quando itens são inseridos, atualizados, ou removidos do DOM. Isto inclui ferramentas para:

Nesta página, nós falaremos apenas sobre transições de entrada, saída, e de lista, mas você pode ver a próxima seção para transição de estados.

Transição Individual de Elementos

Vue disponibiliza um componente encapsulador (wrapper) chamado transition , permitindo que você adicione transição de entrada/saída para qualquer elemento ou componente dentro do seguinte contexto:

Aqui está um exemplo destes em ação:

<div id="demo">
  <button v-on:click="show = !show">
    Alternar
  </button>
  <transition name="fade">
    <p v-if="show">olá</p>
  </transition>
</div>
new Vue({
  el: '#demo',
  data: {
    show: true
  }
})
.fade-enter-active, .fade-leave-active {
  transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active em versões anteriores a 2.1.8 */ {
  opacity: 0;
}

olá

Quando um elemento dentro de um componente transition é inserido ou removido, eis o que acontece:

  1. Vue irá automaticamente procurar se o elemento alvo tem transições CSS ou animações aplicadas. Caso positivo, as classes de transições CSS serão adicionadas/removidas nos momentos apropriados.

  2. Se o componente de transição fornece Gatilhos por JavaScript, estes gatilhos serão invocados nos momentos apropriados.

  3. Se nenhuma transição/animação CSS é detectada e nenhum JavaScript hook é fornecido, as operações de inserção e/ou remoção no DOM serão executadas imediatamente no próximo frame (Nota: isto é um frame de animação do browser, diferente do conceito de nextTick do Vue).

Classes de Transição

Existem seis classes aplicadas para transição de entrada/saída.

  1. v-enter: Inicia o estado de entrada. Aplicada antes do elemento ser inserido, removida depois de um frame.

  2. v-enter-active: Ativa e termina o estado de entrada. Aplicada antes do elemento ser inserido, removida quando a transição/animação termina.

  3. v-enter-to: Disponível apenas nas versões 2.1.8+. Estado final de entrada. Adicionada um frame após o elemento ser inserido (ao mesmo tempo que v-enter é removida), e removida quando a transição/animação termina.

  4. v-leave: Ativa o estado de saída. Aplicada quando a transição de saída é acionada, removida depois de um frame.

  5. v-leave-active: Estado ativo de saída. Aplicada durante toda a fase de saída. Adicionada imediatamente quando a transição de saída é disparada, removida quando a transição/animação termina. Esta classe pode ser usada para definir a duração, atraso e a curva da transição de saída.

  6. v-leave-to: Disponível apenas nas versões 2.1.8+. Estado final da saída. Adicionada um frame após a transição de saída ser disparada (ao mesmo tempo que v-leave é removida), e removida quando a transição/animação termina.

Diagrama de Transição

Cada uma destas classes será prefixada com o nome da transição. Aqui, o prefixo v- é padrão quando você utiliza o elemento <transition> sem nome. Se você, por exemplo, utilizar <transition name="my-transition"> a classe v-enter seria, no entanto, my-transition-enter.

v-enter-active e v-leave-active permitem especificar diferentes progressões de curvas para transição de entrada/saída, das quais você verá um exemplo na seção seguinte.

Transição CSS

Um dos tipos mais comuns de transição se utiliza de transições CSS. Segue um exemplo:

<div id="exemplo-1">
  <button @click="show = !show">
    Alterna renderização
  </button>
  <transition name="slide-fade">
    <p v-if="show">olá</p>
  </transition>
</div>
new Vue({
  el: '#exemplo-1',
  data: {
    show: true
  }
})
/* Animações de entrada e saída podem utilizar diferentes  */
/* funções de duração e de tempo.                          */
.slide-fade-enter-active {
  transition: all .3s ease;
}
.slide-fade-leave-active {
  transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.slide-fade-enter, .slide-fade-leave-to
/* .slide-fade-leave-active em versões anteriores a 2.1.8 */ {
  transform: translateX(10px);
  opacity: 0;
}

olá

Animações CSS

Animações CSS são aplicadas da mesma forma que as transições CSS, sendo que a diferença é que v-enter não é removida imediatamente após o elemento ser inserido, mas sim no evento animationend.

Eis um exemplo, omitindo as regras de prefixo CSS, por uma questão de brevidade:

<div id="exemplo-2">
  <button @click="show = !show">Alternar visualização</button>
  <transition name="bounce">
    <p v-if="show">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis enim libero, at lacinia diam fermentum id. Pellentesque habitant morbi tristique senectus et netus.</p>
  </transition>
</div>
new Vue({
  el: '#exemplo-2',
  data: {
    show: true
  }
})
.bounce-enter-active {
  animation: bounce-in .5s;
}
.bounce-leave-active {
  animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
  0% {
    transform: scale(0);
  }
  50% {
    transform: scale(1.5);
  }
  100% {
    transform: scale(1);
  }
}

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis enim libero, at lacinia diam fermentum id. Pellentesque habitant morbi tristique senectus et netus.

Classes de Transição Personalizadas

Você também pode especificar uma classe de transição personalizada fornecendo os seguintes atributos:

Estes irão substituir os nomes convencionais das classes. Isso é especialmente útil quando você quer combinar o sistema de transição do Vue com outra biblioteca CSS de animação já existente, como Animate.css.

Eis um exemplo:

<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">

<div id="example-3">
  <button @click="show = !show">
    Alterna renderização
  </button>
  <transition
    name="custom-classes-transition"
    enter-active-class="animated tada"
    leave-active-class="animated bounceOutRight"
  >
    <p v-if="show">olá</p>
  </transition>
</div>
new Vue({
  el: '#exemplo-3',
  data: {
    show: true
  }
})

olá

Usando Transição e Animação juntos

Vue precisa escutar eventos para que consiga saber quando uma transição acabou. Os eventos podem ser transitionend ou animationend, dependendo do tipo de regra CSS aplicada. Se você utilizar apenas uma ou outra, Vue detectará automaticamente o tipo correto.

No entanto, em alguns casos, você poderá usar os dois tipos em um só elemento, como por exemplo, ter uma animação CSS que será acionada pelo Vue, juntamente com um efeito de transição CSS acionado pelo hover. Nestes casos, você terá que declarar explicitamente o tipo de evento que você gostaria que o Vue utilizasse em um atributo type, com o valor animation ou transition.

Duração Explícita de Transição

Novo em 2.2.0+

Na maioria dos casos, Vue consegue automaticamente detectar quando a animação terminou. Por padrão, Vue aguarda pelo primeiro evento transitionend ou animationend no elemento raiz da transição. Porém, nem sempre isso é o desejado: nós podemos, por exemplo, ter uma transição coreografada onde alguns dos elementos filhos tem tempos diferentes em relação ao elemento raiz.

Nestes casos você pode especificar uma duração (em milissegundos) usando a propriedade duration no componente <transition>:

<transition :duration="1000">...</transition>

Você também pode especificar valores separados para a duração de entrada e saída:

<transition :duration="{ enter: 500, leave: 800 }">...</transition>

Gatilhos por JavaScript

Você também pode definir os gatilhos (em inglês, JavaScript hooks) nos atributos:

<transition
  v-on:before-enter="beforeEnter"
  v-on:enter="enter"
  v-on:after-enter="afterEnter"
  v-on:enter-cancelled="enterCancelled"

  v-on:before-leave="beforeLeave"
  v-on:leave="leave"
  v-on:after-leave="afterLeave"
  v-on:leave-cancelled="leaveCancelled"
>
  <!-- ... -->
</transition>
// ...
methods: {
  // --------
  // ENTRANDO
  // --------

  beforeEnter: function (el) {
    // ...
  },
  // o callback de finalização é opcional quando
  // utilizado em combinação com CSS
  enter: function (el, done) {
    // ...
    done()
  },
  afterEnter: function (el) {
    // ...
  },
  enterCancelled: function (el) {
    // ...
  },

  // --------
  // SAINDO
  // --------

  beforeLeave: function (el) {
    // ...
  },
  // o callback de finalização é opcional quando
  // utilizado em combinação com CSS
  leave: function (el, done) {
    // ...
    done()
  },
  afterLeave: function (el) {
    // ...
  },
  // leaveCancelled apenas disponível com v-show
  leaveCancelled: function (el) {
    // ...
  }
}

Estes gatilhos podem ser utilizados em combinação com transição/animação CSS ou sozinhos.

Ao utilizar transições puramente JavaScript, os callbacks done para os gatilhos enter e o leave são obrigatórios. Caso contrário, serão invocados de forma síncrona e a transição terá um fim imediato.

Ao utilizar transições puramente JavaScript, é uma boa ideia adicionar explicitamente v-bind:css="false" para que o Vue possa pular a detecção de CSS. Isso também previne que regras CSS interfiram acidentalmente na transição.

Agora vamos mergulhar em um exemplo. Segue uma transição JavaScript com Velocity.js:

<!--
Velocity funciona muito parecido com o jQuery.animate e é uma excelente opção para animações JavaScript
-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>

<div id="exemplo-4">
  <button @click="show = !show">
    Alternar
  </button>
  <transition
    v-on:before-enter="beforeEnter"
    v-on:enter="enter"
    v-on:leave="leave"
    v-bind:css="false"
  >
    <p v-if="show">
      Demo
    </p>
  </transition>
</div>
new Vue({
  el: '#exemplo-4',
  data: {
    show: false
  },
  methods: {
    beforeEnter: function (el) {
      el.style.opacity = 0
      el.style.transformOrigin = 'left'
    },
    enter: function (el, done) {
      Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration: 300 })
      Velocity(el, { fontSize: '1em' }, { complete: done })
    },
    leave: function (el, done) {
      Velocity(el, { translateX: '15px', rotateZ: '50deg' }, { duration: 600 })
      Velocity(el, { rotateZ: '100deg' }, { loop: 2 })
      Velocity(el, {
        rotateZ: '45deg',
        translateY: '30px',
        translateX: '30px',
        opacity: 0
      }, { complete: done })
    }
  }
})

Demo

Transição na Renderização Inicial

Se você quiser aplicar a transição na renderização inicial de um nó, basta adicionar o atributo appear:

<transition appear>
  <!-- ... -->
</transition>

Por padrão, isso utilizará a transição especificada para entrada e saída. Se você desejar, poderá ainda especificar classes CSS específicas:

<transition
  appear
  appear-class="custom-appear-class"
  appear-to-class="custom-appear-to-class" (2.1.8+)
  appear-active-class="custom-appear-active-class"
>
  <!-- ... -->
</transition>

e ganchos JavaScript personalizados

<transition
  appear
  v-on:before-appear="customBeforeAppearHook"
  v-on:appear="customAppearHook"
  v-on:after-appear="customAfterAppearHook"
  v-on:appear-cancelled="customAppearCancelledHook"
>
  <!-- ... -->
</transition>

No exemplo acima, ambos atributo appear ou gatilho v-on:appear farão com que apareça uma transição.

Transição entre Elementos

Nós discutiremos sobre transição entre Componentes em breve, mas você pode realizar transição entre elementos puros utilizando v-if/v-else. Uma das transições de dois elementos mais comum é entre um recipiente de lista e uma mensagem descrevendo uma lista vazia:

<transition>
  <table v-if="items.length > 0">
    <!-- ... -->
  </table>
  <p v-else>Desculpe, nenhum item encontrado.</p>
</transition>

Isso funciona bem, mas existe uma ressalva à qual precisamos estar atentos:

Quando alternamos entre elementos com a mesma tag, você precisa informar o Vue que eles são elementos distintos por meio do atributo único key. Caso contrário, o compilador do Vue irá substituir apenas o conteúdo do elemento por questões de eficiência. Mesmo quando tecnicamente não necessário, é considerado uma boa prática sempre utilizar o atributo key nos múltiplos itens dentro de um componente <transition>

Por exemplo:

<transition>
  <button v-if="isEditing" key="save">
    Salvar
  </button>
  <button v-else key="edit">
    Editar
  </button>
</transition>

Nestes casos você também poderá usar o atributo key para realizar transições entre diferentes estados de um mesmo elemento. Em vez de utilizar v-if e v-else, o exemplo a seguir pode ser reescrito da seguinte forma:

<transition>
  <button v-bind:key="isEditing">
    {{ isEditing ? 'Salvar' : 'Editar' }}
  </button>
</transition>

Também é possível realizar transições entre qualquer número de elementos, utilizando múltiplos v-if ou vinculando um elemento único a uma propriedade dinâmica. Por exemplo:

<transition>
  <button v-if="docState === 'saved'" key="saved">
    Editar
  </button>
  <button v-if="docState === 'edited'" key="edited">
    Salvar
  </button>
  <button v-if="docState === 'editing'" key="editing">
    Cancelar
  </button>
</transition>

Que também pode ser escrito como:

<transition>
  <button v-bind:key="docState">
    {{ buttonMessage }}
  </button>
</transition>
// ...
computed: {
  buttonMessage: function () {
    switch (this.docState) {
      case 'saved': return 'Editar'
      case 'edited': return 'Salvar'
      case 'editing': return 'Cancelar'
    }
  }
}

Modos de Transição

No entanto, ainda temos um problema. Tente clicar no botão abaixo:

Por estarem transitando entre o botão “ligar” e o botão “desligar”, ambos os botões são renderizados - uma transição sai enquanto a outra transição entra. Este é o comportamento padrão do <transition> - entrada e saída acontecem simultaneamente.

Às vezes isso funciona perfeitamente, como quando realizamos transições de itens que são absolutamente posicionados no topo uns dos outros:

E também utilizar translate para que se pareça com uma transição slide:

No entanto, transições de entrada e saída simultâneas nem sempre são desejadas. Neste caso, o Vue oferece alguns modos de transição alternativos:

Agora vamos atualizar a transição para os nossos botões ligar/desligar com out-in:

<transition name="fade" mode="out-in">
  <!-- ... os botões ... -->
</transition>

Com a adição de um atributo, corrigimos nossa transição original sem ter de adicionar qualquer estilo especial.

O modo in-out não é utilizado com frequência, mas às vezes pode ser útil para um efeito de transição ligeiramente diferente. Vamos tentar combiná-lo com a transição slide-fade em que trabalhamos anteriormente:

Bem legal, certo?

Transições entre Componentes

Transições entre componentes são ainda mais simples - nem precisamos do atributo key. Em vez disso, encapsulamos em um componente dinâmico:

<transition name="component-fade" mode="out-in">
  <component v-bind:is="view"></component>
</transition>
new Vue({
  el: '#transition-components-demo',
  data: {
    view: 'v-a'
  },
  components: {
    'v-a': {
      template: '<div>Component A</div>'
    },
    'v-b': {
      template: '<div>Component B</div>'
    }
  }
})
.component-fade-enter-active, .component-fade-leave-active {
  transition: opacity .3s ease;
}
.component-fade-enter, .component-fade-leave-to
/* .component-fade-leave-active em versões anteriores a 2.1.8 */ {
  opacity: 0;
}

Transições em Listas

Até agora, temos transições para:

Então, que tal ter uma lista de itens e renderizá-los simultaneamente com o v-for, por exemplo? Neste caso, utilizaremos o componente <transition-group>. Antes de entrarmos em um exemplo, existem algumas coisas que é importante saber sobre este componente:

Transição de Entrada/Saída de Lista

Agora vamos analisar um exemplo, transitando entrada e saída com as mesmas classes CSS que usamos anteriormente:

<div id="list-demo" class="demo">
  <button v-on:click="add">Adicionar</button>
  <button v-on:click="remove">Remover</button>
  <transition-group name="list" tag="p">
    <span v-for="item in items" v-bind:key="item" class="list-item">
      {{ item }}
    </span>
  </transition-group>
</div>
new Vue({
  el: '#list-demo',
  data: {
    items: [1,2,3,4,5,6,7,8,9],
    nextNum: 10
  },
  methods: {
    randomIndex: function () {
      return Math.floor(Math.random() * this.items.length)
    },
    add: function () {
      this.items.splice(this.randomIndex(), 0, this.nextNum++)
    },
    remove: function () {
      this.items.splice(this.randomIndex(), 1)
    },
  }
})
.list-item {
  display: inline-block;
  margin-right: 10px;
}
.list-enter-active, .list-leave-active {
  transition: all 1s;
}
.list-enter, .list-leave-to /* .list-leave-active em versões anteriores a 2.1.8 */ {
  opacity: 0;
  transform: translateY(30px);
}
{{ item }}

Há um problema com este exemplo. Quando você adiciona ou remove um item, aqueles em torno dele se encaixam instantaneamente ao invés de fazer a transição suavemente. Nós iremos corrigir isto mais tarde.

Transições de Movimento de Lista

O componente <transition-group> tem outro truque na manga. Ele não só tem animação de entrada e saída, como também na mudança de posição. O único conceito novo que você precisa saber para usar este recurso é a adição de da classe v-move, a qual é inserida quando os itens estão mudando suas posições. Assim como outras classes, elas serão prefixadas com o valor fornecido pelo atributo name e você poderá especificar manualmente uma classe com o atributo move-class.

Esta classe é útil para especificar o tempo de transição ou a suavidade da curva, como você pode ver adiante:

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script>

<div id="flip-list-demo" class="demo">
  <button v-on:click="shuffle">Misturar</button>
  <transition-group name="flip-list" tag="ul">
    <li v-for="item in items" v-bind:key="item">
      {{ item }}
    </li>
  </transition-group>
</div>
new Vue({
  el: '#flip-list-demo',
  data: {
    items: [1,2,3,4,5,6,7,8,9]
  },
  methods: {
    shuffle: function () {
      this.items = _.shuffle(this.items)
    }
  }
})
.flip-list-move {
  transition: transform 1s;
}
  • {{ item }}
  • Isto pode parecer mágica, mas internamente Vue está aplicando uma técnica de animação chamada FLIP para suavemente transitar elementos da posição antiga para a posição nova utilizando transformações CSS.

    Nós podemos combinar esta técnica com a nossa implementação anterior para animar qualquer mudança na nossa lista!

    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script>
    
    <div id="list-complete-demo" class="demo">
      <button v-on:click="shuffle">Misturar</button>
      <button v-on:click="add">Adicionar</button>
      <button v-on:click="remove">Remover</button>
      <transition-group name="list-complete" tag="p">
        <span
          v-for="item in items"
          v-bind:key="item"
          class="list-complete-item"
        >
          {{ item }}
        </span>
      </transition-group>
    </div>
    new Vue({
      el: '#list-complete-demo',
      data: {
        items: [1,2,3,4,5,6,7,8,9],
        nextNum: 10
      },
      methods: {
        randomIndex: function () {
          return Math.floor(Math.random() * this.items.length)
        },
        add: function () {
          this.items.splice(this.randomIndex(), 0, this.nextNum++)
        },
        remove: function () {
          this.items.splice(this.randomIndex(), 1)
        },
        shuffle: function () {
          this.items = _.shuffle(this.items)
        }
      }
    })
    .list-complete-item {
      transition: all 1s;
      display: inline-block;
      margin-right: 10px;
    }
    .list-complete-enter, .list-complete-leave-to
    /* .list-complete-leave-active em versões anteriores a 2.1.8 */ {
      opacity: 0;
      transform: translateY(30px);
    }
    .list-complete-leave-active {
      position: absolute;
    }
    {{ item }}

    É importante notar que as transições FLIP não funcionam com elementos display: inline. Como alternativa, você pode usar display: inline-block ou colocar os elementos dentro de um contexto flex.

    Estas animações FLIP também não são limitadas a um único eixo. Itens em uma grade multidimensional também podem ser transitados:

    Sudoku para preguiçosos

    Clique no botão misturar até ganhar.

    {{ cell.number }}

    Escalonamento de Transições de Lista

    Ao comunicar com transições JavaScript por meio de atributos de dados, também é possível escalonar as transições em uma lista:

    <script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
    
    <div id="staggered-list-demo">
      <input v-model="query">
      <transition-group
        name="staggered-fade"
        tag="ul"
        v-bind:css="false"
        v-on:before-enter="beforeEnter"
        v-on:enter="enter"
        v-on:leave="leave"
      >
        <li
          v-for="(item, index) in computedList"
          v-bind:key="item.msg"
          v-bind:data-index="index"
        >{{ item.msg }}</li>
      </transition-group>
    </div>
    new Vue({
      el: '#staggered-list-demo',
      data: {
        query: '',
        list: [
          { msg: 'Bruce Lee' },
          { msg: 'Jackie Chan' },
          { msg: 'Chuck Norris' },
          { msg: 'Jet Li' },
          { msg: 'Kung Fury' }
        ]
      },
      computed: {
        computedList: function () {
          var vm = this
          return this.list.filter(function (item) {
            return item.msg.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1
          })
        }
      },
      methods: {
        beforeEnter: function (el) {
          el.style.opacity = 0
          el.style.height = 0
        },
        enter: function (el, done) {
          var delay = el.dataset.index * 150
          setTimeout(function () {
            Velocity(
              el,
              { opacity: 1, height: '1.6em' },
              { complete: done }
            )
          }, delay)
        },
        leave: function (el, done) {
          var delay = el.dataset.index * 150
          setTimeout(function () {
            Velocity(
              el,
              { opacity: 0, height: 0 },
              { complete: done }
            )
          }, delay)
        }
      }
    })
  • {{ item.msg }}
  • Transições Reutilizáveis

    Transições podem ser reutilizadas por meio do sistema de componentes do Vue. Para criar uma transição reutilizável, tudo o que você precisa fazer é inserir um componente <transition> ou <transition-group> em sua raiz, e então adicionar qualquer componente filho dentro do componente de transição.

    Eis um exemplo utilizando um modelo de componente:

    Vue.component('my-special-transition', {
      template: '\
        <transition\
          name="very-special-transition"\
          mode="out-in"\
          v-on:before-enter="beforeEnter"\
          v-on:after-enter="afterEnter"\
        >\
          <slot></slot>\
        </transition>\
      ',
      methods: {
        beforeEnter: function (el) {
          // ...
        },
        afterEnter: function (el) {
          // ...
        }
      }
    })

    E componentes funcionais são especialmente bem adequados para esta tarefa:

    Vue.component('my-special-transition', {
      functional: true,
      render: function (createElement, context) {
        var data = {
          props: {
            name: 'very-special-transition',
            mode: 'out-in'
          },
          on: {
            beforeEnter: function (el) {
              // ...
            },
            afterEnter: function (el) {
              // ...
            }
          }
        }
        return createElement('transition', data, context.children)
      }
    })

    Transições Dinâmicas

    Sim, até as transições no Vue são orientadas a dados (data-driven)! O exemplo mais básico de uma transição dinâmica vincula o atributo name a uma propriedade dinâmica.

    <transition v-bind:name="transitionName">
      <!-- ... -->
    </transition>

    Isto pode ser útil quando você tiver definido transições/animações CSS usando as convenções de classes de transição do Vue e quiser alternar entre elas.

    No entanto, qualquer atributo de transição pode ser vinculado dinamicamente. Não apenas atributos: como gatilhos de eventos são métodos, possuem acesso a qualquer dado no contexto. Isto significa que suas transições JavaScript podem se comportar de forma diferente dependendo do estado de seu componente.

    <script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
    
    <div id="dynamic-fade-demo" class="demo">
      Fade In: <input type="range" v-model="fadeInDuration" min="0" v-bind:max="maxFadeDuration">
      Fade Out: <input type="range" v-model="fadeOutDuration" min="0" v-bind:max="maxFadeDuration">
      <transition
        v-bind:css="false"
        v-on:before-enter="beforeEnter"
        v-on:enter="enter"
        v-on:leave="leave"
      >
        <p v-if="show">olá</p>
      </transition>
      <button
        v-if="stop"
        v-on:click="stop = false; show = false"
      >Começar a animar</button>
      <button
        v-else
        v-on:click="stop = true"
      >Pare!</button>
    </div>
    new Vue({
      el: '#dynamic-fade-demo',
      data: {
        show: true,
        fadeInDuration: 1000,
        fadeOutDuration: 1000,
        maxFadeDuration: 1500,
        stop: true
      },
      mounted: function () {
        this.show = false
      },
      methods: {
        beforeEnter: function (el) {
          el.style.opacity = 0
        },
        enter: function (el, done) {
          var vm = this
          Velocity(el,
            { opacity: 1 },
            {
              duration: this.fadeInDuration,
              complete: function () {
                done()
                if (!vm.stop) vm.show = false
              }
            }
          )
        },
        leave: function (el, done) {
          var vm = this
          Velocity(el,
            { opacity: 0 },
            {
              duration: this.fadeOutDuration,
              complete: function () {
                done()
                vm.show = true
              }
            }
          )
        }
      }
    })
    Fade In: Fade Out:

    olá

    Finalmente, a última forma para a criação de transições dinâmicas é por meio de componentes que aceitam que suas props possam mudar a natureza da transição a ser utilizada. Pode parecer clichê, mas o único limite é sua imaginação.