通过Volocity.js源码看JS如何顺滑操作动画
Opened this issue · 0 comments
顺滑的动画
在网页开发圈子里有一种误解,那就是认为CSS动画是网络中唯一可以实现高性能动画的方法。因为CSS可以借助硬件加速把动画直接交给GPU处理。
事实上,基于JavaScript的动画与基于CSS的动画一样快。之所以JS动画会卡顿,或许是因为你使用定时器(setTimeout、setInterval)去处理动画了,但这不是JS的错,而是你的使用方法错了。
基于JS的动画有如下的优点:
- 动画中止
- 动画反转
- 动画管理
CSS非常适合实现悬停状态的动画效果(例如:当鼠标位于链接上方时,链接变成蓝色)这类的微互动,这也是通常情况下基本的网页所包含的动画。
Velocity.js核心原理
Velocity.js是一个著名的动画库。这是个轻量级的库,但是功能却异常丰富。
GitHub地址奉上:https://github.com/julianshapiro/velocity
为了研究JS是如何优雅处理动画的,我们通过一段动画效果,观察火焰图去解析:
核心JS是:
document.querySelector("#v").velocity(
{
opacity: 0.5,
left: 1000,
},
{
duration: 2000,
}
);
下图是帧率和CPU利用率的示意图:
在CPU那一行,可以看到,有很多执行点,我们放大其中一个:
我们可以看到Animation Frame Fired
,其实就是requestAnimationFrame()
回调被触发了,接着执行tick和setPropertyValue。我们一个一个看:
点击跳转到源码:
跳转到rAFShim,可以看到这是对 requestAnimationFrame
的调用,tick
是它的回调:
rAFProxy = (callback: FrameRequestCallback) => {
return setTimeout(callback, Math.max(0, FRAME_TIME - (performance.now() - lastTick)));
},
rAFShim = window.requestAnimationFrame || rAFProxy;
跳转到 setPropertyValue
:
function setPropertyValue(element, propertyName, propertyValue, fn) {
var noCache = NoCacheNormalizations.has(propertyName),
data = !noCache && Data(element);
if (noCache || data && data.cache[propertyName] !== propertyValue) {
// By setting it to undefined we force a true "get" later
if (!noCache) {
data.cache[propertyName] = propertyValue || undefined;
}
fn = fn || getNormalization(element, propertyName);
if (fn) {
fn(element, propertyValue);
}
if (Velocity$$1.debug >= 2) {
console.info("Set \"" + propertyName + "\": \"" + propertyValue + "\"", element);
}
}
}
我们继续深究上面的fn函数,发现它是 getSetStyle
返回的函数,函数最后会设置元素的style属性:
function getSetStyle(propertyName) {
return function (element, propertyValue) {
if (propertyValue === undefined) {
return computePropertyValue(element, propertyName);
}
element.style[propertyName] = propertyValue;
};
}
至此,我们可以理顺 Velocity.js 的核心原理:
- 当我们通过velocity去设置某个元素的最终样式,velocity会计算出初始值,在演示里是 opacity 和 left
- 然后通过注册
requestAnimationFrame()
回调去计算动画的中间态,并应用在元素上
Velocity.js 是通过计算值处理动画效果的中间值的。所以对几何长宽、颜色、透明度这些值非常友好。
不仅如此,Velocity.js还可以终止动画,也可以反转动画,这些都是CSS设置动画办不到的,JS可以通过在执行requestAnimationFrame
回调前终止动画,并且通过记录历史中间态并反转。
搭配React使用
Velocity.js 搭配 React 使用的库叫 velocity-react。
GitHub地址奉上:https://github.com/google-fabric/velocity-react
velocity-react 暴露两个组件接口:
- VelocityComponent,添加动画,为子组件注册动画效果;
- VelocityTransitionGroup,添加过渡效果(显示和隐藏组件,切换组件),这个组件里面的所有子组件的mount、unmount都会触发过渡效果,底层依赖
TransitionGroup
(react-transition-group)组件。
还有一个API接口:velocityHelpers,用以注册动画效果的。
参考
《JavaScript网页动画设计》
Velocity.js
https://github.com/google-fabric/velocity-react