Animazioni
Scelte tecnologiche
Le animazioni sono spesso utilizzate per rendere più dinamiche le applicazioni. Attualmente, i browser offrono un buon supporto per le animazioni CSS e sono disponibili diverse librerie che forniscono animazioni veloci basate su JavaScript. Esiste anche una Web API in fase di sviluppo e un polyfill se si desidera utilizzare tecnologie all'avanguardia.
Mithril.js non fornisce API di animazione native, in quanto le opzioni esistenti sono più che sufficienti per creare animazioni complesse e di alta qualità. Tuttavia, Mithril.js offre degli hook per semplificare la gestione di animazioni in specifici scenari in cui tradizionalmente l'implementazione risulta complessa.
Animazione alla creazione di un elemento
Animare un elemento tramite CSS al momento della sua creazione è estremamente semplice. È sufficiente aggiungere un'animazione a una classe CSS come si farebbe normalmente:
.fancy {
animation: fade-in 0.5s;
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
var FancyComponent = {
view: function () {
return m('.fancy', 'Hello world');
},
};
m.mount(document.body, FancyComponent);
Animazione alla rimozione di un elemento
La difficoltà nell'animare un elemento prima della sua rimozione risiede nel dover attendere il completamento dell'animazione prima di poterlo effettivamente rimuovere. Fortunatamente, Mithril.js offre l'hook onbeforeremove
che consente di posticipare la rimozione di un elemento.
Creiamo un'animazione exit
che sfuma l'opacity
da 1 a 0.
.exit {
animation: fade-out 0.5s;
}
@keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
Ora creiamo un componente di esempio che mostra e nasconde il FancyComponent
creato nella sezione precedente:
var on = true;
var Toggler = {
view: function () {
return [
m(
'button',
{
onclick: function () {
on = !on;
},
},
'Toggle'
),
on ? m(FancyComponent) : null,
];
},
};
Successivamente, modifichiamo FancyComponent
per farlo svanire quando viene rimosso:
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', 'Hello world');
},
};
vnode.dom
fa riferimento all'elemento DOM radice del componente (<div class="fancy">
). Utilizziamo l'API classList
per aggiungere la classe exit
a <div class="fancy">
.
Quindi restituiamo una Promise
che si risolve quando viene generato l'evento animationend
. Quando si restituisce una Promise
da onbeforeremove
, Mithril.js attende che la Promise
sia risolta e solo allora rimuove l'elemento. In questo caso, attende il completamento dell'animazione di uscita.
Possiamo verificare che entrambe le animazioni di entrata e di uscita funzionino montando il componente Toggler
:
m.mount(document.body, Toggler);
Si noti che l'hook onbeforeremove
si attiva solo sull'elemento che perde il proprio parentNode
quando viene rimosso dal DOM. Questo comportamento è intenzionale e serve a prevenire un'esperienza utente indesiderata, in cui ogni possibile animazione di uscita sulla pagina verrebbe eseguita ad ogni cambio di route. Se l'animazione di uscita non viene eseguita, assicurarsi di collegare l'handler onbeforeremove
il più in alto possibile nella gerarchia del DOM per garantire che il codice di animazione venga eseguito.
Performance
Quando si creano animazioni, si consiglia di utilizzare solo le regole CSS opacity
e transform
, poiché queste possono essere accelerate via hardware dai browser moderni e offrono prestazioni migliori rispetto all'animazione di proprietà come top
, left
, width
e height
.
Si consiglia inoltre di evitare la regola box-shadow
e selettori come :nth-child
, poiché anche queste sono opzioni che richiedono molte risorse. Se si desidera animare un box-shadow
, si consiglia di applicare la regola box-shadow
a uno pseudo elemento e animare invece l'opacità di tale elemento. Altre operazioni che possono richiedere molte risorse includono l'uso di immagini di grandi dimensioni o che vengono ridimensionate dinamicamente, e la sovrapposizione di elementi con valori di position
diversi (ad esempio, un elemento con posizionamento assoluto sopra un elemento con posizionamento fisso).