動畫
技術選擇
動畫經常被用來讓應用程式更具活力。現今,瀏覽器對 CSS 動畫有良好的支援,並且有 各種 函式庫 提供快速的基於 JavaScript 的動畫。如果您喜歡走在尖端,還有一個即將推出的 Web API 和一個 polyfill。
Mithril.js 本身並不提供動畫 API,因為這些其他選項足以實現豐富、複雜的動畫。然而,Mithril.js 確實提供了鉤子,以便在某些傳統上難以製作動畫的特定情況下,讓開發更輕鬆。
元素創建時的動畫
在元素創建時,通過 CSS 動畫為元素添加效果非常簡單。只需像平常一樣將動畫添加到 CSS 類別即可:
.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);
元素移除時的動畫
在移除元素前進行動畫的問題在於,我們必須等到動畫完成後才能實際移除該元素。幸運的是,Mithril.js 提供了 onbeforeremove
鉤子,允許我們延遲移除元素。
讓我們創建一個 exit
動畫,將 opacity
從 1 漸變到 0。
.exit {
animation: fade-out 0.5s;
}
@keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
現在讓我們創建一個示範用的元件,顯示和隱藏我們在前一節中創建的 FancyComponent
:
var on = true;
var Toggler = {
view: function () {
return [
m(
'button',
{
onclick: function () {
on = !on;
},
},
'Toggle'
),
on ? m(FancyComponent) : null,
];
},
};
接下來,讓我們修改 FancyComponent
,使其在移除時淡出:
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
指向元件的根 DOM 元素(<div class="fancy">
)。我們在這裡使用 classList API 將 exit
類別添加到 <div class="fancy">
。
然後我們返回一個 Promise,該 Promise 會在 animationend
事件觸發時被解析。當我們從 onbeforeremove
返回一個 promise 時,Mithril.js 會等待直到 promise 被解析,然後才會移除該元素。在這種情況下,它會等待退出動畫完成。
我們可以通過掛載 Toggler
元件來驗證進入和退出動畫是否正常運作。
m.mount(document.body, Toggler);
請注意,只有當元素從 DOM 中分離,且失去 parentNode
時,onbeforeremove
鉤子才會被觸發。此行為是設計使然,旨在避免潛在的突兀使用者體驗。如果您的退出動畫未運行,請確保將 onbeforeremove
處理程序附加到元件樹中合適的高層位置,以確保您的動畫程式碼被調用。
性能
在創建動畫時,建議您僅使用 opacity
和 transform
的 CSS 規則,因為這些規則可以被現代瀏覽器進行硬體加速,相較於動畫 top
、left
、width
和 height
,能產生更好的性能。
還建議您避免使用 box-shadow
規則和像 :nth-child
這樣的選擇器,因為這些也是資源密集型選項。如果您想為 box-shadow
製作動畫,請考慮 將 box-shadow
規則置於偽元素上,並改為對該元素的 opacity 製作動畫。其他可能消耗較多資源的項目包括大型或動態縮放的圖像,以及具有不同 position
值(例如,固定元素上的絕對定位元素)的重疊元素。