JavaScript 动画应该通过 requestAnimationFrame 实现。该内置方法允许设置回调函数,以便在浏览器准备重绘时运行。那通常很快,但确切的时间取决于浏览器。
callback 得到一个参数 —— 从页面加载开始经过的毫秒数。这个时间也可通过调用 performance.now() 得到。
当页面在后台时,根本没有重绘,因此回调将不会运行:动画将被暂停并且不会消耗资源。那很棒。
这是设置大多数动画的 helper 函数 animate:
function animate({ timing, draw, duration }) {let start = performance.now();requestAnimationFrame(function animate(time) {// timeFraction 从 0 增加到 1let timeFraction = (time - start) / duration;if (timeFraction > 1) timeFraction = 1;// 计算当前动画状态let progress = timing(timeFraction);draw(progress); // 绘制if (timeFraction < 1) {requestAnimationFrame(animate);}});}
参数:
- duration —— 动画运行的总毫秒数。
- timing —— 计算动画进度的函数。获取从 0 到 1 的小数时间,返回动画进度,通常也是从 0 到 1。
- draw —— 绘制动画的函数。
当然我们可以改进它,增加更多花里胡哨的东西,但 JavaScript 动画不是经常用到。它们用于做一些有趣和不标准的事情。因此,您大可在必要时再添加所需的功能。
JavaScript 动画可以使用任何时序函数。与 CSS 不同,我们不仅限于 Bezier 曲线。
draw 也是如此:我们可以将任何东西动画化,而不仅仅是 CSS 属性。
练习:跳动的小球
http://js.jirengu.com/gucogeceve/1/edit?html,js,output
<!DOCTYPE HTML><html><head><script src="https://js.cx/libs/animate.js"></script><style>#field {height: 200px;border-bottom: 3px black groove;position: relative;}#ball {position: absolute;cursor: pointer;}</style></head><body><div id="field"><img src="https://js.cx/clipart/ball.svg" width="40" height="40" id="ball"></div><script>function makeEaseOut(timing) {return function(timeFraction) {return 1 - timing(1 - timeFraction);}}function bounce(timeFraction) {for (let a = 0, b = 1, result; 1; a += b, b /= 2) {if (timeFraction >= (7 - 4 * a) / 11) {return -Math.pow((11 - 6 * a - 11 * timeFraction) / 4, 2) + Math.pow(b, 2)}}}function quad(timeFraction) {return Math.pow(timeFraction, 2);}ball.onclick = function() {let height = field.clientHeight - ball.clientHeight;let width = 100animate({duration: 2000,timing: makeEaseOut(bounce),draw(progress) {ball.style.top = height * progress + 'px'}});animate({duration: 2000,timing: makeEaseOut(quad),draw(progress) {ball.style.left = width * progress + 'px'}});};</script></body></html>
