跳到主要内容

渲染与图形

requestAnimationFrame 是什么,有什么作用?

答案
方法主要用途执行时机优势典型场景
requestAnimationFrame浏览器动画帧调度重绘前与刷新率同步,节能流畅JS动画、进度条等

补充说明

  • requestAnimationFrame 会在浏览器每次重绘前自动调用回调,通常约每秒60次,能保证动画与屏幕刷新同步,减少卡顿和掉帧。
  • 返回的ID可用于 cancelAnimationFrame 取消动画,适合实现高性能动画循环。
  • 与 setTimeout/setInterval 相比,requestAnimationFrame 更节能且动画更平滑,页面切换到后台时会自动暂停,节省资源。
let id
function loop () {
// 动画逻辑
id = requestAnimationFrame(loop)
}
loop()
// 取消动画
cancelAnimationFrame(id)
提示

推荐所有涉及 DOM 动画的场景优先使用 requestAnimationFrame,提升性能和流畅度。

延伸阅读

canvas 是如何处理复杂事件交互的?

答案

核心概念

Canvas 本身不具备 DOM 事件绑定能力,复杂事件交互需通过监听容器事件并结合图形坐标判定实现。常见做法是监听鼠标或触摸事件,计算事件点在 canvas 内的坐标,再判断是否命中特定图形,实现点击、悬停、拖拽等交互。

详细实现步骤

  • 监听事件:在 canvas 或其父容器上监听 mousemovemousedownmouseuptouchstart 等事件。
  • 坐标转换:通过 getBoundingClientRect 获取 canvas 的位置,将事件的 clientX/Y 转换为 canvas 内部坐标。
  • 命中检测:遍历所有图形对象,判断事件点是否落在某个图形区域(如圆形、矩形等)。
  • 状态管理:可维护图形对象数组,记录每个图形的状态(如选中、悬停),实现动态交互效果。

代码示例

const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d')
const shapes = [
{ type: 'circle', x: 100, y: 100, radius: 50 },
{ type: 'rectangle', x: 200, y: 200, width: 100, height: 50 }
]

canvas.addEventListener('mousemove', function (event) {
const rect = canvas.getBoundingClientRect()
const mouseX = event.clientX - rect.left
const mouseY = event.clientY - rect.top
shapes.forEach(shape => {
if (shape.type === 'circle' && isPointInCircle(mouseX, mouseY, shape)) {
ctx.fillStyle = 'red'
} else {
ctx.fillStyle = 'blue'
}
drawShape(shape)
})
})

function isPointInCircle (x, y, { x: cx, y: cy, radius }) {
const dx = x - cx
const dy = y - cy
return dx * dx + dy * dy <= radius * radius
}

function drawShape (shape) {
if (shape.type === 'circle') {
ctx.beginPath()
ctx.arc(shape.x, shape.y, shape.radius, 0, Math.PI * 2)
ctx.fill()
} else if (shape.type === 'rectangle') {
ctx.fillRect(shape.x, shape.y, shape.width, shape.height)
}
}

开发建议

  • 复杂交互建议封装图形对象和事件处理逻辑,或使用如 Fabric.js、Konva.js 等第三方库简化开发。
  • 需注意每次交互后需清空并重绘 canvas,避免残影。

延伸阅读

48%