Animações
Escolhas Tecnológicas
Animações são frequentemente utilizadas para dar vida às aplicações. Atualmente, os navegadores oferecem bom suporte para animações CSS, e existem várias bibliotecas que fornecem animações rápidas baseadas em JavaScript. Há também uma Web API futura e um polyfill se você deseja utilizar tecnologias de ponta.
O Mithril.js não oferece APIs de animação diretamente, já que essas outras opções são mais do que suficientes para criar animações ricas e complexas. No entanto, o Mithril.js oferece hooks para facilitar a implementação de animações em casos específicos onde tradicionalmente é difícil fazê-las funcionar.
Animação na criação de elementos
Animar um elemento com CSS no momento da sua criação é muito simples. Basta adicionar uma animação a uma classe CSS normalmente:
.fancy {
animation: fade-in 0.5s;
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
var FancyComponent = {
view: function () {
return m('.fancy', 'Olá mundo');
},
};
m.mount(document.body, FancyComponent);
Animação na remoção de elementos
O desafio ao animar a remoção de um elemento é que precisamos esperar a conclusão da animação antes de realmente remover o elemento. Felizmente, o Mithril.js oferece o hook onbeforeremove
que nos permite adiar a remoção de um elemento.
Vamos criar uma animação de saída que faz a opacidade ir de 1 para 0.
.exit {
animation: fade-out 0.5s;
}
@keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
Agora vamos criar um componente de exemplo que mostra e esconde o FancyComponent
que criamos na seção anterior:
var on = true;
var Toggler = {
view: function () {
return [
m(
'button',
{
onclick: function () {
on = !on;
},
},
'Toggle'
),
on ? m(FancyComponent) : null,
];
},
};
Em seguida, vamos modificar o FancyComponent
para que ele desapareça quando removido:
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', 'Olá mundo');
},
};
vnode.dom
aponta para o elemento DOM raiz do componente (<div class="fancy">
). Usamos a API classList
aqui para adicionar a classe exit
a <div class="fancy">
.
Em seguida, retornamos uma Promise que é resolvida quando o evento animationend
é disparado. Quando retornamos uma Promise de onbeforeremove
, o Mithril.js espera até que a Promise seja resolvida e só então remove o elemento. Neste caso, ele espera que a animação de saída termine.
Podemos verificar se as animações de entrada e saída funcionam montando o componente Toggler
:
m.mount(document.body, Toggler);
Observe que o hook onbeforeremove
só é disparado no elemento que perde seu parentNode
quando um elemento é desanexado do DOM. Este comportamento é intencional e existe para evitar uma experiência de usuário potencialmente desagradável, onde todas as animações de saída possíveis na página seriam executadas em uma mudança de rota. Se sua animação de saída não estiver sendo executada, certifique-se de adicionar o handler onbeforeremove
o mais alto possível na hierarquia de elementos para garantir que seu código de animação seja chamado.
Performance
Ao criar animações, é recomendado que você use apenas as regras CSS opacity
e transform
, já que estas podem ter aceleração de hardware nos navegadores modernos e produzir melhor desempenho do que animar top
, left
, width
e height
.
Também é recomendado que você evite a regra box-shadow
e seletores como :nth-child
, já que estas também são opções que demandam muitos recursos. Se você quiser animar um box-shadow
, considere colocar a regra box-shadow
em um pseudo-elemento e animar a opacidade desse elemento. Outras coisas que podem afetar o desempenho incluem imagens grandes ou redimensionadas dinamicamente e elementos sobrepostos com diferentes valores de position
(por exemplo, um elemento com position: absolute
sobre um elemento com position: fixed
).