在Web开发中,创建平滑且高效的动画是一项常见的需求。requestAnimationFrame
API 提供了一种优化动画渲染的方法,它能确保动画与浏览器的刷新率同步,从而提高性能和用户体验。本文将详细介绍 requestAnimationFrame
的工作原理、使用方法及实际应用案例,帮助你更好地掌握这一关键技术。
1. requestAnimationFrame
的原理
requestAnimationFrame
是一种用于在浏览器的下一帧渲染时机执行指定函数的API。其核心优势在于能够与浏览器的刷新率同步,通常是每秒60帧(60Hz),从而确保动画的流畅性和效率。当调用 requestAnimationFrame(callback)
时,浏览器会在下一次重绘之前调用 callback
函数。如果浏览器处于空闲状态或标签页不在活动窗口中,requestAnimationFrame
会自动调整调用频率以节省资源。
2. 使用 requestAnimationFrame
requestAnimationFrame
接受一个函数作为参数,该函数将在下一帧渲染前被调用。函数内部可以访问一个可选的时间戳参数,表示从页面加载开始到现在的时间(以毫秒为单位)。
javascript// 调用 requestAnimationFrame
requestAnimationFrame(function(timestamp) {
// 在这里编写动画逻辑
});
3. 实战案例:粒子系统动画
让我们通过创建一个粒子系统动画来深入理解 requestAnimationFrame
的使用。
html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Particle Animation with requestAnimationFrame</title>
<style>
canvas {
display: block;
margin: auto;
background: #222;
}
</style>
</head>
<body>
<canvas id="particleCanvas"></canvas>
<script>
// 获取 canvas 元素和 2D 上下文
const canvas = document.getElementById('particleCanvas');
const ctx = canvas.getContext('2d');
// 初始化画布尺寸
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// 粒子类定义
class Particle {
constructor(x, y) {
this.x = x;
this.y = y;
this.size = Math.random() * 10 + 5;
this.speedX = (Math.random() - 0.5) * 10;
this.speedY = (Math.random() - 0.5) * 10;
}
update() {
// 更新粒子位置
this.x += this.speedX;
this.y += this.speedY;
// 边界反弹
if (this.x > canvas.width || this.x < 0) this.speedX *= -1;
if (this.y > canvas.height || this.y < 0) this.speedY *= -1;
}
draw() {
// 绘制粒子
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
ctx.fill();
}
}
let particles = [];
let requestId;
// 初始化粒子
function init() {
for (let i = 0; i < 100; i++) {
particles.push(new Particle(Math.random() * canvas.width, Math.random() * canvas.height));
}
}
// 动画循环
function drawParticles() {
// 清除画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 更新并绘制所有粒子
particles.forEach(particle => {
particle.update();
particle.draw();
});
// 请求下一帧
requestId = requestAnimationFrame(drawParticles);
}
// 启动动画
init();
drawParticles();
// 示例:添加按钮来控制动画
const toggleButton = document.createElement('button');
toggleButton.textContent = "Stop Animation";
document.body.appendChild(toggleButton);
toggleButton.addEventListener('click', () => {
if (requestId) {
// 取消动画
cancelAnimationFrame(requestId);
toggleButton.textContent = "Start Animation";
requestId = null;
} else {
// 重新开始动画
requestId = requestAnimationFrame(drawParticles);
toggleButton.textContent = "Stop Animation";
}
});
</script>
</body>
</html>
效果如下: