toFrankie / blog

种一棵树,最好的时间是十年前。其次,是现在。
20 stars 1 forks source link

requestAnimationFrame 使用 #289

Open toFrankie opened 1 year ago

toFrankie commented 1 year ago

配图源自 Freepik

一、requestAnimationFrame

MDN 介绍可知:

调用 window.requestAnimationFrame() 方法告知浏览器,希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。

从这句话可以看出,它相比 setTimeout 等 API 的优势之一是减少 DOM 重绘的次数。

语法也很简单:

window.requestAnimationFrame(callback)

它接受一个回调函数(即下一次重绘之前更新动画帧所调用的函数),并返回一个非零且唯一的 requestId(可以传给 window.cancelAnimationFrame() 以取消回调函数)。

回调函数将会被传入一个 DOMHighResTimeStamp 参数,表示 requestAnimationFrame() 开始去执行回调函数的时刻。

看一下 MDN 给出的一个示例:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      #foo {
        width: 100px;
        height: 100px;
        background-color: rebeccapurple;
      }
    </style>
  </head>
  <body>
    <div id="foo"></div>
    <script>
      let start
      const element = document.getElementById('foo')

      function step(timestamp) {
        if (start === undefined) start = timestamp
        const elapsed = timestamp - start

        // 这里使用 `Math.min()` 确保元素刚好停在 200px 的位置。
        element.style.transform = `translateX(${Math.min(0.1 * elapsed, 200)}px)`

        if (elapsed < 2000) {
          // 在两秒后停止动画
          window.requestAnimationFrame(step)
        }
      }

      window.requestAnimationFrame(step)
    </script>
  </body>
</html>

效果可看下 👉 CodeSandbox

帧动画回调函数的执行次数取决于「屏幕刷新率」,以 60Hz(表示每秒钟图像刷新的次数)的屏幕来说,约 16.7ms 会刷新一次,也就是说 requestAnimationFrame() 的回调函数约 16.7ms 就会执行一次。

而且,在多数浏览器中,当 requestAnimationFrame() 处于后台标签页或者被隐藏的 <iframe> 元素里,它会被暂停调用以提升性能和电池寿命。

未完待续...