
Mis últimos dos proyectos me lanzaron al JAMstack. SPA, gestión de contenido sin cabeza, generación estática… lo que sea. Más importante aún, me dieron la oportunidad de aprender Vue.js. Más que “Crear una aplicación de tareas pendientes” Vue.js, pude enviar aplicaciones Vue de la vida real y listas para producción.
La agencia detrás de Snipcart (Spektrum) quería comenzar a usar marcos JavaScript desacoplados para sitios pequeños y medianos. Sin embargo, antes de usarlos en proyectos de clientes, eligieron experimentar con ellos mismos. Después de que algunos de mis compañeros tuvieron experiencias infructuosas con React, me dieron luz verde para crear prototipos de algunas aplicaciones en Vue. Esta creación de prototipos se transformó en aplicaciones Vue completas para Spektrum conectadas a un CMS sin cabeza. Primero, dediqué tiempo a descubrir cómo modelar y representar nuestros datos de manera adecuada. Luego me sumergí de cabeza en las transformaciones de Vue para aplicar una capa de pulido muy necesaria en nuestros dos proyectos.
He preparado demostraciones en vivo en los repositorios de CodePen y GitHub para acompañar este artículo.
Esta publicación profundiza en Vue.js y las herramientas que ofrece con su sistema de transición. Se supone que ya se siente cómodo con los conceptos básicos de las transiciones de Vue.js y CSS. En aras de la brevedad y la claridad, no entraremos en la “lógica” utilizada en la demostración.
Manejo de transiciones y animaciones de Vue.js
Las animaciones y las transiciones pueden darle vida a su sitio y atraer a los usuarios a explorar. Las animaciones y las transiciones son una parte integral del diseño de UX y UI. Sin embargo, es fácil equivocarse. En situaciones complejas como lidiar con listas, puede ser casi imposible razonar sobre ellas cuando se confía en JavaScript y CSS nativos. Cada vez que pregunto a los desarrolladores de back-end por qué no les gusta el front-end con tanta vehemencia, su respuesta suele ser algo así como “… animaciones”.
Incluso para aquellos de nosotros que nos sentimos atraídos por el campo por la necesidad de crear microinteracciones complejas y transiciones de página fluidas, no es un trabajo fácil. A menudo necesitamos confiar en CSS por motivos de rendimiento, incluso cuando trabajamos en un entorno principalmente de JavaScript, y esa interrupción en el entorno puede ser difícil de gestionar.
Aquí es donde intervienen frameworks como Vue.js, tomando las conjeturas y cadenas torpes de setTimeout
funciones a partir de transiciones.
La diferencia entre transiciones y animaciones
Los términos transición y animación a menudo se usan indistintamente, pero en realidad son cosas diferentes.
- A
transition
es un cambio en las propiedades de estilo de un elemento que se va a cambiar en un solo paso. A menudo se manejan únicamente a través de CSS. - Un
animation
es más complejo. Por lo general, son de varios pasos y, a veces, se ejecutan de forma continua. Las animaciones a menudo recurren a JavaScript para retomar el punto en el que falla la falta de lógica de CSS.
Puede ser confuso, ya que agregar una clase podría desencadenar una transición o una animación. Aún así, es una distinción importante al ingresar al mundo de Vue porque ambos tienen enfoques y cajas de herramientas muy diferentes.
Aquí hay un ejemplo de transiciones en uso en el sitio de Spektrum:
Usar transiciones
La forma más sencilla de lograr efectos de transición en su página es a través de Vue <transition>
componente. Hace las cosas tan simples que casi se siente como hacer trampa. Vue detectará si se están utilizando animaciones o transiciones CSS y alternará automáticamente las clases en el contenido transicionado, lo que permite un sistema de transición perfectamente sincronizado y un control completo.
El primer paso es identificar nuestro alcance. Le decimos a Vue que anteponga las clases de transición con modal
, por ejemplo, configurando el componente name
atributo. Luego, para desencadenar una transición, todo lo que necesita hacer es alternar la visibilidad del contenido usando el v-if
o v-show
atributos Vue agregará/eliminará las clases en consecuencia.
Hay dos “direcciones” para las transiciones: enter
(para un elemento que va de oculto a visible) y leave
(para un elemento que va de visible a oculto). Luego, Vue proporciona 3 “ganchos” que representan diferentes períodos de tiempo en la transición:
.modal-enter-active
/.modal-leave-active
: Estos estarán presentes durante toda la transición y deben usarse para aplicar su declaración de transición CSS. También puede declarar estilos que deben aplicarse de principio a fin..modal-enter
/.modal-leave
: Use estas clases para definir cómo se ve su elemento antes de que comience la transición..modal-enter-to
/.modal-leave-to
: Probablemente ya lo haya adivinado, estos determinan los estilos hacia los que desea hacer la transición, el estado “completo”.
Para visualizar todo el proceso, eche un vistazo a este gráfico de la documentación de Vue:
¿Cómo se traduce esto en código? Digamos que simplemente queremos aparecer y desaparecer gradualmente, unir las piezas se vería así:
<button class="modal__open" @click="modal = true">Help</button>
<transition name="modal">
<section v-if="modal" class="modal">
<button class="modal__close" @click="modal = false">×</button>
</section>
</transition>
.modal-enter-active,
.modal-leave-active { transition: opacity 350ms }
.modal-enter,
.modal-leave-to { opacity: 0 }
.modal-leave,
.modal-enter-to { opacity: 1 }
Esta es probablemente la implementación más básica que encontrará. Tenga en cuenta que este sistema de transición también puede manejar cambios de contenido. Por ejemplo, podría reaccionar a un cambio en la dinámica de Vue <component>
.
<transition name="slide">
<component :is="selectedView" :key="selectedView"/>
</transition>
.slide-enter { transform: translateX(100%) }
.slide-enter-to { transform: translateX(0) }
.slide-enter-active { position: absolute }
.slide-leave { transform: translateX(0) }
.slide-leave-to { transform: translateX(-100%) }
.slide-enter-active,
.slide-leave-active { transition: all 750ms ease-in-out }
siempre que el selectedView
cambios, el componente antiguo se deslizará hacia la izquierda y el nuevo entrará por la derecha.
Aquí hay una demostración que usa estos conceptos:
Vea la demostración de transición y grupo de transición de Pen VueJS por Nicolas Udy (@udyux) en CodePen.
Transiciones en listas
Las cosas se ponen interesantes cuando empezamos a trabajar con listas. Ya sean viñetas o una cuadrícula de publicaciones de blog, Vue le brinda la <transition-group>
componente.
Vale la pena señalar que mientras el <transition>
componente en realidad no representa un elemento, <transition-group>
lo hace. El comportamiento predeterminado es utilizar un <span>
pero puede anular esto configurando el tag
atributo en el <transition-group>
.
El otro problema es que todos los elementos de la lista deben tener un único key
atributo. Vue puede realizar un seguimiento de cada elemento individualmente y optimizar su rendimiento. En nuestra demostración, estamos recorriendo la lista de empresas, cada una de las cuales tiene una identificación única. Entonces podemos configurar nuestra lista así:
<transition-group name="company" tag="ul" class="content__list">
<li class="company" v-for="company in list" :key="company.id">
<!-- ... -->
</li>
</transition-group>
La característica más impresionante de transition-group
es cómo Vue maneja los cambios en el orden de la lista de manera tan fluida. Para ello, está disponible una clase de transición adicional, .company-move
(al igual que el active
clases para entrar y salir), que se aplicarán para enumerar elementos que se mueven pero permanecerán visibles.
En la demostración, lo desglosé un poco más para mostrar cómo aprovechar diferentes estados para obtener un resultado final más limpio. Aquí hay una versión simplificada y ordenada de los estilos:
/* base */
.company {
backface-visibility: hidden;
z-index: 1;
}
/* moving */
.company-move {
transition: all 600ms ease-in-out 50ms;
}
/* appearing */
.company-enter-active {
transition: all 300ms ease-out;
}
/* disappearing */
.company-leave-active {
transition: all 200ms ease-in;
position: absolute;
z-index: 0;
}
/* appear at / disappear to */
.company-enter,
.company-leave-to {
opacity: 0;
}
Utilizando backface-visibility: hidden
en un elemento, incluso en ausencia de transformaciones 3D, garantizará transiciones sedosas de 60 fps y evitará la representación borrosa del texto durante las transformaciones al engañar al navegador para que aproveche la aceleración de hardware.
En el fragmento anterior, configuré el estilo base en z-index: 1
. Esto asegura que los elementos que permanecen en la página siempre aparecerán sobre los elementos que se van. también aplico un absolute
posicionamiento a los elementos que se van para eliminarlos del flujo natural, desencadenando el move
transición en el resto de los elementos.
¡Eso es todo lo que necesitamos! El resultado es, francamente, casi mágico.
Uso de animaciones
Las posibilidades y los enfoques para la animación en Vue son prácticamente infinitos, por lo que elegí una de mis técnicas favoritas para mostrar cómo puede animar sus datos.
Vamos a utilizar la biblioteca TweenLite de GSAP para aplicar funciones de aceleración a los cambios de nuestro estado y permitir que la reactividad ultrarrápida de Vue refleje esto en el DOM. Vue se siente tan cómodo trabajando con SVG en línea como con HTML.
Crearemos un gráfico lineal con 5 puntos, espaciados uniformemente a lo largo del eje X, cuyo eje Y representará un porcentaje. Puedes echar un vistazo aquí al resultado.
Vea la animación de la ruta Pen SVG con VueJS y TweenLite de Nicolas Udy (@udyux) en CodePen.
Comencemos con la lógica de nuestro componente.
new Vue({
el: '#app',
// this is the data-set that will be animated
data() {
return {
points: { a: -1, b: -1, c: -1, d: -1, e: -1 }
}
},
// this computed property builds an array of coordinates that
// can be used as is in our path
computed: {
path() {
return Object.keys(this.points)
// we need to filter the array to remove any
// properties TweenLite has added
.filter(key => ~'abcde'.indexOf(key))
// calculate X coordinate for 5 points evenly spread
// then reverse the data-point, a higher % should
// move up but Y coordinates increase downwards
.map((key, i) => [i * 100, 100 - this.points[key]])
}
},
methods: {
// our randomly generated destination values
// could be replaced by an array.unshift process
setPoint(key) {
let duration = this.random(3, 5)
let destination = this.random(0, 100)
this.animatePoint({ key, duration, destination })
},
// start the tween on this given object key and call setPoint
// once complete to start over again, passing back the key
animatePoint({ key, duration, destination }) {
TweenLite.to(this.points, duration, {
[key]: destination,
ease: Sine.easeInOut,
onComplete: this.setPoint,
onCompleteParams: [key]
})
},
random(min, max) {
return ((Math.random() * (max - min)) + min).toFixed(2)
}
},
// finally, trigger the whole process when ready
mounted() {
Object.keys(this.points).forEach(key => {
this.setPoint(key)
})
}
});
Ahora para la plantilla.
<main id="app" class="chart">
<figure class="chart__content">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-20 -25 440 125">
<path class="chart__path" :d="`M${path}`"
fill="none" stroke="rgba(255, 255, 255, 0.3)"
stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<text v-for="([ x, y ]) in path" :x="x - 10" :y="y - 7.5"
font-size="10" font-weight="200" fill="currentColor">
{{ 100 - (y | 0) + '%' }}
</text>
</svg>
</figure>
</main>
Observe cómo unimos nuestro path
propiedad calculada al elemento de la ruta d
atributo. Hacemos algo similar con los nodos de texto que generan el valor actual para ese punto. Cuando TweenLite actualiza los datos, Vue reacciona instantáneamente y mantiene el DOM sincronizado.
¡Eso es realmente todo lo que hay que hacer! Por supuesto, se aplicaron estilos adicionales para hacer las cosas bonitas, lo que en este punto puede darse cuenta de que es más trabajo que la animación en sí.
Demostraciones en vivo (CodePen) y repositorio de GitHub
¡Adelante, navegue por las demostraciones en vivo o analice/reutilice el código en nuestro repositorio de código abierto!
- El repositorio de GitHub de vue-animate
- El repositorio de GitHub de vue-transitions
- La demostración de transición y grupo de transición de Vue.js
- La demostración de animación de la ruta SVG
Conclusión
Siempre he sido un fanático de las animaciones y las transiciones en la web, pero también soy un fanático del rendimiento. Como resultado, siempre soy muy cauteloso cuando se trata de confiar en JavaScript. Sin embargo, al combinar la reactividad increíblemente rápida y de bajo costo de Vue con su capacidad para administrar transiciones CSS puras, realmente tendría que exagerar para tener problemas de rendimiento.
Es impresionante que un marco tan poderoso pueda ofrecer una API tan simple pero manejable. La demostración de animación, incluido el estilo, se creó en solo 45 minutos. Y si se descuenta el tiempo que se tardó en configurar los datos simulados utilizados en la transición de la lista, se puede lograr en menos de 2 horas. Ni siquiera quiero imaginar el proceso inductor de migraña de construir configuraciones similares sin Vue, ¡mucho menos cuánto tiempo llevaría!
¡Ahora sal y sé creativo! Los casos de uso van mucho más allá de lo que hemos visto en este post: la única limitación verdadera es tu imaginación. No olvide consultar la sección de transiciones y animaciones en la documentación de Vue.js para obtener más información e inspiración.
Esta publicación apareció originalmente en el blog de Snipcart. ¿Tienes comentarios, preguntas? ¡Agrégalos a continuación!