动画
技术选型
动画可以使应用更生动。现在的浏览器对 CSS 动画的支持已经很好了,而且还有各种库可以提供基于 JavaScript 的动画。如果你喜欢最前沿的技术的话,还有 Web API 和 polyfill。
Mithril 本身不提供任何动画 API,因为已经有很多其他方案来实现丰富、复杂的动画了。但是,Mithril 提供了钩子,在用传统方法实现动画有困难的情况下,可以使用钩子来实现。
元素创建时的动画
元素创建时的动画效果,可以通过 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 提供了一个 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) {
setTimeout(resolve, 500)
})
},
view: function() {
return m(".fancy", "Hello world")
}
}
vnode.dom
指向组件的根 DOM 元素(<div class="fancy">
),我们在该元素上添加了一个类 exit
。
我们返回一个 Promise,并在半秒钟后完成。当我们从 onbeforeremove
返回 promise 时,Mithril 会保持等待,直到 promise 被完成,元素才会被移除。在这个例子中,它等待了半秒,给了 exit 足够的时间来完成动画。
我们把 Toggler
组件渲染到页面上,就能测试这个渐变动画效果了:
m.mount(document.body, Toggler)
性能
使用 CSS 动画时,建议你只在 opacity
和 transform
属性上使用动画,因为这两个属性的动画会启用硬件加速,会比 top
、left
、width
、height
属性的动画有更高的性能。
同时也建议你避免使用 box-shadow
属性和类似 :nth-child
这样的选择器,因为这些属性的动画也是很占用资源的。如果你想在 box-shadow
属性上使用动画,建议把 box-shadow
属性放在伪元素中,并用伪元素的 opacity
的变化来代替 box-shadow
的变化。其他比较耗费资源的包括:大型图片或者动态可缩放的图片、使用不同 position
的值进行重叠的元素。