动画

很长时间以来,计时器和循环间隔一直都是JavaScript动画的最核心技术。无论是setInterval()还是 setTimeout()都不十分精确。为它们传入的第二个参数,实际上只是指定了把动画代码添加到浏览器 UI 线程队列中以等待执行的时间。如果队列前面已经加入了其他任务,那动画代码就要等前面的任务完成后再执行。简言之,以毫秒表示的延迟时间并不代表到时候一定会执行动画代码,而仅代表到时候会把代码添加到任务队列中。如果UI线程繁忙,比如忙于处理用户操作,那么即使把代码加入队列也不会立即执行。

CSS 变换和动画的优势在于浏览器知道动画什么时候开始,因此会计算出正确的循环间隔,在恰当的时候刷新 UI。而对于 JavaScript 动画,浏览器无从知晓什么时候开始。

requestAnimationFrame

告诉浏览器您希望执行动画并请求浏览器在下一次重绘之前调用指定的函数来更新动画。若您想要在下次重绘时产生另一个动画画面,您的回调例程必须调用它。语法:

var aid = window.requestAnimationFrame(callback);
  • callback

一个指定函数的参数,该函数在下次重新绘制动画时调用。

  • 返回值

整数,请求 ID ,是回调列表中唯一的标识。是个非零值,没别的意义。你可以传这个值给 window.cancelAnimationFrame() 以取消回调函数。

CSS 圆周运动

<div class="container">
    <div id="ball"></div>
</div>
.container{
    position: absolute;
    top:50%;
    left: 50%;
    transform: translate(-50%,-50%);
    width: 400px;
    height: 400px;
    background: #f1f1f1;
}
#ball{
    position: absolute;
    top: 0;
    left: 0;
    width: 20px;
    height: 20px;
    background: green;
    border-radius: 50%;
    transform-origin: 200px 200px;
    animation: circle 4s linear infinite;
}
@keyframes circle{
    0%{
        transform: rotate(0deg);
    }
    100%{
        transform: rotate(360deg);
    }
}

JS 圆周运动

沿用上述CSS圆周运动中的 HTML 及 CSS,注释其 animation 属性。

#ball{
    ...
    /*animation: circle 4s linear infinite;*/
}
function startCircle(el){
    let startTime = Date.now(); // 获取启动时间
    let cycle = 4000; // 多少秒转一周
    requestAnimationFrame(function update(){
        let currentTime = Date.now(); // 获取当前时间
        let p = (currentTime - startTime) / cycle; // 计算转动多少周
        el.style.transform = `rotate(${360 * p }deg)` // 转化为角度
        requestAnimationFrame(update) // 下一次渲染继续执行
    })
}
var ball = document.getElementById('ball');
startCircle(ball);