关于 requestAnimationFrame

requestAnimationFrame 是浏览器提供的一个专门用于动画的 API。它的作用是在下一次浏览器重绘之前调用指定的回调函数,通常以每秒 60 次(取决于屏幕刷新率)的频率执行,从而实现流畅的动画。

主要特点:

  1. 与屏幕刷新率同步:避免不必要的绘制,减少 CPU/GPU 消耗。
  2. 自动暂停:当页面切换到后台标签页时,requestAnimationFrame 会暂停,节省资源。
  3. 精确时间控制:回调函数会收到一个 DOMHighResTimeStamp 参数(从页面加载开始的时间戳),方便计算时间差实现匀速运动。
  4. 替代 setInterval/setTimeout:更高性能,更适合动画。

基本用法:

function animate() {
  // 更新动画状态(如改变位置、旋转角度等)
  // 绘制新的一帧
  requestAnimationFrame(animate); // 递归调用,形成运动循环
}
requestAnimationFrame(animate); // 启动动画

通常还需要配合 cancelAnimationFrame 来停止动画。


简单动画案例:使用 Circle 类

下面通过三个简单案例演示如何使用 requestAnimationFrame 控制圆类的运动。每个案例都包含一个 Circle 类,并在 Canvas 上绘制动画。

基础 Circle 类定义

class Circle {
  constructor(x, y, radius, color) {
    this.x = x;
    this.y = y;
    this.radius = radius;
    this.color = color;
  }

  draw(ctx) {
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
    ctx.fillStyle = this.color;
    ctx.fill();
    ctx.closePath();
  }
}

案例 1:圆在水平方向来回移动(边界反弹)

<canvas id="canvas1" width="600" height="200" style="border:1px solid #ccc"></canvas>
<script>
  const canvas = document.getElementById('canvas1');
  const ctx = canvas.getContext('2d');

  class Circle {
    constructor(x, y, radius, color) {
      this.x = x;
      this.y = y;
      this.radius = radius;
      this.color = color;
    }
    draw(ctx) {
      ctx.beginPath();
      ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
      ctx.fillStyle = this.color;
      ctx.fill();
      ctx.closePath();
    }
  }

  const circle = new Circle(50, 100, 20, 'blue');
  let speedX = 3;

  function animate() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    // 更新位置
    circle.x += speedX;
    // 边界反弹(碰到左右边界反转速度)
    if (circle.x + circle.radius > canvas.width || circle.x - circle.radius < 0) {
      speedX = -speedX;
    }
    circle.draw(ctx);
    requestAnimationFrame(animate);
  }
  animate();
</script>

案例 2:圆的半径周期性变化(缩放动画)

<canvas id="canvas2" width="600" height="200" style="border:1px solid #ccc"></canvas>
<script>
  const canvas = document.getElementById('canvas2');
  const ctx = canvas.getContext('2d');

  class Circle {
    constructor(x, y, radius, color) {
      this.x = x;
      this.y = y;
      this.radius = radius;
      this.color = color;
    }
    draw(ctx) {
      ctx.beginPath();
      ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
      ctx.fillStyle = this.color;
      ctx.fill();
      ctx.closePath();
    }
  }

  const circle = new Circle(300, 100, 20, 'green');
  let radiusDelta = 0.5;
  let minRadius = 10;
  let maxRadius = 40;

  function animate() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    // 改变半径
    circle.radius += radiusDelta;
    if (circle.radius > maxRadius || circle.radius < minRadius) {
      radiusDelta = -radiusDelta;
    }
    circle.draw(ctx);
    requestAnimationFrame(animate);
  }
  animate();
</script>

案例 3:画笔跟随鼠标移动(圆跟随鼠标 + 颜色渐变)

<canvas id="canvas3" width="600" height="200" style="border:1px solid #ccc"></canvas>
<script>
  const canvas = document.getElementById('canvas3');
  const ctx = canvas.getContext('2d');

  class Circle {
    constructor(x, y, radius, color) {
      this.x = x;
      this.y = y;
      this.radius = radius;
      this.color = color;
    }
    draw(ctx) {
      ctx.beginPath();
      ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
      ctx.fillStyle = this.color;
      ctx.fill();
      ctx.closePath();
    }
  }

  const circle = new Circle(300, 100, 25, 'red');

  // 监听鼠标移动
  canvas.addEventListener('mousemove', (e) => {
    const rect = canvas.getBoundingClientRect();
    circle.x = e.clientX - rect.left;
    circle.y = e.clientY - rect.top;
    // 动态改变颜色(基于鼠标 X 坐标)
    const hue = (circle.x / canvas.width) * 360;
    circle.color = `hsl(${hue}, 100%, 50%)`;
  });

  function animate() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    circle.draw(ctx);
    requestAnimationFrame(animate);
  }
  animate();
</script>

总结

  • requestAnimationFrame 是现代浏览器实现流畅动画的标准方法,尤其适合与 Canvas 或 WebGL 结合使用。
  • 通过封装一个 Circle 类,可以轻松管理圆的位置、半径、颜色等属性,并在每一帧更新这些属性,实现丰富多彩的动画效果。
  • 以上三个案例分别演示了 位移缩放鼠标交互,可作为进一步开发复杂动画的基础。
Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐