动画
技术选型
动画常被用于增强应用程序的生动性。现代浏览器对 CSS 动画提供了良好的支持,并且有各种各样的 库可以实现快速的、基于 JavaScript 的动画。如果你对新技术感兴趣,还可以关注即将推出的 Web Animations 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
事件触发时变为 resolved 状态。当我们从 onbeforeremove
返回一个 promise 时,Mithril.js 会等待直到 promise 被 resolve,才会移除该元素。在此例中,它会等待退出动画完成。
我们可以通过挂载 Toggler
组件来验证进入和退出动画是否都有效:
m.mount(document.body, Toggler);
请注意,onbeforeremove
钩子仅在元素从 DOM 中分离时触发,即当元素失去其 parentNode
时。这种行为的设计目的是为了避免潜在的突兀用户体验,例如页面上所有可能的退出动画都在路由更改时运行。如果退出动画没有生效,请确保将 onbeforeremove
处理程序绑定到尽可能高的层级,以确保动画代码能够被执行。
性能
在创建动画时,建议仅使用 opacity
和 transform
CSS 规则,因为这些规则可以由现代浏览器进行硬件加速,并且比动画 top
、left
、width
和 height
具有更好的性能。
还建议避免使用 box-shadow
规则以及类似 :nth-child
的选择器,因为它们都是资源密集型的选项。如果需要为 box-shadow
添加动画效果,可以考虑将 box-shadow
规则应用于一个伪元素,并修改该伪元素的 opacity 属性。其他可能造成性能开销的因素包括大型或动态缩放的图片,以及 position
属性值不同的重叠元素(例如,一个绝对定位元素覆盖在一个固定定位元素之上)。