Animaciones
Opciones tecnológicas
Las animaciones se utilizan a menudo para dar vida a las aplicaciones. Hoy en día, los navegadores tienen un buen soporte para las animaciones CSS, y existen varias bibliotecas que proporcionan animaciones rápidas basadas en JavaScript. También hay una API web emergente y un polyfill si prefieres usar las últimas novedades.
Mithril.js no proporciona una API de animación propia, ya que estas otras opciones son más que suficientes para lograr animaciones ricas y complejas. Sin embargo, Mithril.js ofrece hooks para facilitar el desarrollo en casos específicos donde tradicionalmente es difícil implementar animaciones.
Animación en la creación de elementos
Animar un elemento con CSS al crearlo es muy sencillo. Simplemente añade una animación a una clase CSS:
.fancy {
animation: fade-in 0.5s;
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
var FancyComponent = {
view: function () {
return m('.fancy', 'Hola mundo');
},
};
m.mount(document.body, FancyComponent);
Animación en la eliminación de elementos
El desafío de animar antes de eliminar un elemento radica en que debemos esperar a que la animación se complete antes de poder eliminarlo realmente. Afortunadamente, Mithril.js ofrece el hook onbeforeremove
que nos permite diferir la eliminación de un elemento.
Creemos una animación que desvanezca la opacidad
de 1 a 0.
.exit {
animation: fade-out 0.5s;
}
@keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
Ahora creemos un componente que muestre y oculte el FancyComponent
que creamos en la sección anterior:
var on = true;
var Toggler = {
view: function () {
return [
m(
'button',
{
onclick: function () {
on = !on;
},
},
'Alternar'
),
on ? m(FancyComponent) : null,
];
},
};
A continuación, modifiquemos FancyComponent
para que se desvanezca cuando se elimine:
var FancyComponent = {
onbeforeremove: function (vnode) {
vnode.dom.classList.add('exit');
return new Promise(function (resolve) {
vnode.dom.addEventListener('animationend', resolve);
});
},
view: function () {
return m('.fancy', 'Hola mundo');
},
};
vnode.dom
apunta al elemento DOM raíz del componente (<div class="fancy">
). Utilizamos la API classList
aquí para añadir la clase exit
a <div class="fancy">
.
Luego devolvemos una Promesa que se resuelve cuando se dispara el evento animationend
. Cuando devolvemos una promesa desde onbeforeremove
, Mithril.js espera hasta que la promesa se resuelva y solo entonces elimina el elemento. En este caso, espera a que termine la animación de salida.
Podemos verificar que tanto las animaciones de entrada como de salida funcionan montando el componente Toggler
:
m.mount(document.body, Toggler);
Ten en cuenta que el hook onbeforeremove
solo se dispara en el elemento que pierde su parentNode
cuando un elemento se elimina del DOM. Este comportamiento es intencional y existe para evitar una experiencia de usuario potencialmente incómoda donde cada animación de salida concebible en la página se ejecutaría en un cambio de ruta. Si tu animación de salida no se está ejecutando, asegúrate de adjuntar el handler onbeforeremove
lo más arriba posible en la jerarquía que tenga sentido para asegurar que se llame a tu código de animación.
Rendimiento
Al crear animaciones, se recomienda que solo utilices las reglas CSS opacity
y transform
, ya que estas pueden ser aceleradas por hardware por los navegadores modernos y ofrecen un mejor rendimiento que animar top
, left
, width
y height
.
También se recomienda que evites la regla box-shadow
y los selectores como :nth-child
, ya que también son opciones que requieren muchos recursos. Si quieres animar un box-shadow
, considera poner la regla box-shadow
en un pseudoelemento, y animar la opacidad de ese elemento en su lugar. Otras cosas que pueden ser costosas son las imágenes grandes o escaladas dinámicamente y los elementos superpuestos con diferentes valores de position
(por ejemplo, un elemento posicionado absolutamente sobre un elemento fijo).