El conocimiento es el nuevo dinero.
Aprender es la nueva manera en la que inviertes
Acceso Cursos

Aprende de Animaciones y transiciones con Vue3

· 7 min de lectura
Aprende de Animaciones y transiciones con Vue3

Como los frontend profesionales que somos 😎, tenemos que procurar especializarnos en la experiencia de usuario, por lo que debemos encargarnos de que nuestra aplicación sea rápida y fácil de usar para que nuestros usuarios no se sienta frustrados o peor aún no usen nuestra aplicación por la escasez de retroalimentación en sus acciones.

Y es que existen situaciones en las que nuestra aplicación toma unos microsegundos en responder, y a pesar de que el backend desarrolle una API super rápida, nosotros nos encargamos que los usuarios no perciban este delay entre los requests, y claro, no solo al momento de hacer requests, sino también en la presentación de tarjetas o de otros componentes.

Además, nuestra aplicación se ve fabulosa en increíble cuando le agregamos transiciones😏.

Con lo anteriormente mencionado, te voy a mostrar como Vuejs resuelve nuestros dolores de cabeza con las animaciones de una forma elegante, que, lo más difícil será que hagamos algo de buen gusto😵‍💫, porque créeme (e lo dice alguien con mal gusto), una vez que te muestre lo fácil que es, querrás animarlo todo jajaja 🥳.

Ahora, manos a la obra

Para este mini proyecto vamos a hacer uso de Vite  escogeremos la opción de Vue, para este tutorial también usaremos Vue3, que en lo personal es increíble, por ahora ubiquémonos donde vas a crear el proyecto y hagamos lo siguiente.

vuejs npm create vite@latest
need to install the following packages:
Create-vite@latest
Ok to proceed? (y) y
? Project name: > vue-animations

Tomamos la opción de vue y javascript como lenguaje de programación y seleccionamos la opción de vue y javascript como lenguaje de programación.

✔︎Select a framework > - vue
? Select a variant > - Use arrow-keys. Return to submit
> Javascript
Typescript
Customize with create-vue
Nuxt

Ahora con nuestro proyecto creado, ingresemos y corramos el comando para activar el servidor.

-> vuejs cd vue-animations && npm install
-> vue-animations npm run dev && code .

Con esto listo, ingresamos a nuestro navegador al puerto que nos indica la consola, este caso el puerto localhost:5173, y tenemos lo siguiente

Ahora, vamos a crear un TODO list super rápido, para ir al punto principal del post que es la animación, ahora dentro de nuestro archivo App.vue colocaremos lo siguiente:

<script setup>
import { ref } from 'vue';
import item from './components/item.vue';

const list = ref([])
const input = ref('')

function addItem() {
  list.value.push(input.value)
  clearField()
}

function removeItem(item) {
  const idx = list.value.indexOf(item)
  list.value.splice(idx, 1)
}

function clearField() {
  input.value = ''
}

</script>

<template>
  <div>
    <a href="https://vitejs.dev" target="_blank">
      <img src="/vite.svg" class="logo" alt="Vite logo" />
    </a>
    <a href="https://vuejs.org/" target="_blank">
      <img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
    </a>
  </div>
  <div class="wrapper">
    <div class="input-wrapper">
      <input v-model="input" type="text" class="input">
    </div>
    <button class="button" @click="addItem">
      Add item
    </button>
  </div>
  <div class="list-wrapper">
      <item
        v-for="(item, index) in list"
        :key="index"
        :item="item"
        @remove-item="removeItem" />
  </div>
</template>

<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
  transition: filter 300ms;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
.wrapper {
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 12px;
}
.input-wrapper {
  border: 1px solid #41b883;
  border-radius: 4px;
  padding: 5px 10px;
  background-color: transparent;
}

.input {
  border: none;
  color: white;
  font-size: 16px;
  background-color: transparent;
}
.input:focus {
  outline: none
}

.button {
  width: fit-content;
  background-color: #41b883;
}
.button:active {
  border: none;
  outline: none;
}

.list-wrapper {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 12px;
}

</style>

Como observamos dentro del archivo App.vue tenemos un componente que espera a que se le agregue las transiciones, en este caso nuestra lista de items, pero antes de trabajar con el debemos crear el component Item.vue, para eso vamos a hacer lo siguiente dentro de la carpeta components y agregamos esto:

<script setup>
const emit = defineEmits(['remmove-item'])

const props = defineProps({
  item: {
    type: String,
    required: true
  }
})

function removeItem(item) {
  emit('remove-item', item)
}

</script>

<template>
  <div v-if="item.length" class="item-wrapper">
    <p class="item">
      {{ item }}
    </p>
    <button class="button" @click="removeItem(item)">
      Borrar
    </button>
  </div>
</template>

<style scoped>
.item-wrapper {
  width: 100%;
  margin-bottom: 8px;
  padding: 2px 12px;
  border-radius: 8px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  background-color: #ab4bff;
}

.item {
  color: white;
  font-size: 16px;
}

.button {
  background: #ed7777;
  font-size: 12px;
}
</style>
OJO: En nuestro componente item como se observa esta haciendo uso de un emit, si quieres conocer más de cómo usar esta gran herramient emit, revisa este post

Perfecto, con esto ya nuestra funcionalidad de agregar items y removerlos de la lista ha sido completada, y deberíamos estar observando lo siguiente:

Y como se puede observar, los items aparecen y desaparecen de una forma brusca, y es justo eso lo que animaremos para que tenga un efecto más smooth.

Quiero hacerte una aclaratoria, antes de continuar, la etiqueta que usaremos en nuestro template, TransitionGroup, tiene la misma implementación que la etiqueta, Transition, solo la primera nos permite animar un grupo de elementos como el nombre lo indica, mientras que la segunda es para un único elemento, respectivamente.

Así que teniendo en cuenta que la idea con ambas etiquetas, continuemos

Ahora que estamos usando la etiqueta TransitionGroup porque estamos iterando uno o más items, gracias a nuestro v-for, la idea es que se anime cada tarjeta de item cuando aparezca o desaparezca. OK, muchas atención con lo que comentaré a continuación, porque este es el eje principal de las animaciones cuando ingresan en nuestra pantalla o cuando se van.

Agreguemos los siguientes cambios en nuestro archivo App.vue

<script setup>
import { ref } from 'vue';
import item from './components/item.vue';

const list = ref([])
const input = ref('')

function addItem() {
  list.value.push(input.value)
  clearField()
}

function removeItem(item) {
  const idx = list.value.indexOf(item)
  list.value.splice(idx, 1)
}

function clearField() {
  input.value = ''
}

</script>

<template>
  <div>
    <a href="https://vitejs.dev" target="_blank">
      <img src="/vite.svg" class="logo" alt="Vite logo" />
    </a>
    <a href="https://vuejs.org/" target="_blank">
      <img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
    </a>
  </div>
  <div class="wrapper">
    <div class="input-wrapper">
      <input v-model="input" type="text" class="input">
    </div>
    <button class="button" @click="addItem">
      Add item
    </button>
  </div>
  <div class="list-wrapper">
    <TransitionGroup name="slide">
      <item
        v-for="(item, index) in list"
        :key="index"
        :item="item"
        @remove-item="removeItem" />
    </TransitionGroup>
  </div>
</template>

<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
  transition: filter 300ms;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
.wrapper {
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 12px;
}
.input-wrapper {
  border: 1px solid #41b883;
  border-radius: 4px;
  padding: 5px 10px;
  background-color: transparent;
}

.input {
  border: none;
  color: white;
  font-size: 16px;
  background-color: transparent;
}
.input:focus {
  outline: none
}

.button {
  width: fit-content;
  background-color: #41b883;
}
.button:active {
  border: none;
  outline: none;
}

.list-wrapper {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 12px;
}

.slide-enter-from {
  opacity: 0;
  transform: translate(15px);
}
.slide-enter-to {
  opacity: 1;
  transform: translate(0px);
}
.slide-enter-active {
  transition: all 500ms ease-in;
}
.slide-leave-from {
  opacity: 1;
  transform: translate(0px);
}
.slide-leave-to {
  opacity: 0;
  transform: translate(-15px);
}
.slide-leave-active {
  transition: all 500ms ease-in;
}
</style>

En la etiqueta TransitionGroup tenemos el atributo name, esto nos permite identificar cada transición que hagamos, y podemos usar más de una a la vez dentro de un solo template, y el uso de este atributo se ve reflejado en el css, puesto que allí se construye la animación como clases, facilitándonos la implementación de nuestra animación.

Cuando ingresa nuestro elemento

Dentro de nuestro css, podemos observar ciertas etiquetas, las que tienen en medio la palabra enter son las encargadas de animar la entrada del componente, en este caso el item, mientras que las clases con la palabra leave se usan al momento de que el componente desaparezca.

Veámoslo de una forma más clara.

ANIMACIÓN DE ENTRADA

.slide(name del transitionGroup)-enter(aparece elemento)-from(estado inicial)
.slide(name del transitionGroup)-enter(aparece elemento)-to(estado final)
.slide(name del transitionGroup)-enter(aparece elemento)-active(animación activada)

Además, la configuración con la que queremos ver nuestra animación de salida, cuando removemos el item de la lista es el siguiente

ANIMACIÓN DE SALIDA

.slide(name del transitionGroup)-leave(desaparece elemento)-from(estado inicial)
.slide(name del transitionGroup)-leave(desaparece elemento)-to(estado final)
.slide(name del transitionGroup)-leave(desaparece elemento)-active(animación activada)

Y sin más que agregar espero que haya quedado super claro cómo funciona las animaciones dentro de Vue3 y como el framework conoce lo complicado que puede ser aplicar animaciones en CSS y como tiene herramientas que facilite nuestras implementaciones.

Ahora el resto te queda a ti, empieza a practicar, que lo fácil es hacer que funcione el código, lo difícil es tener buen gusto en animaciones jajajajaj, mucha suerte con eso 🥸.

Plataforma de cursos gratis sobre programación