
Canvas 动画中矩形“越移越宽”并非尺寸变化,而是因未清除上一帧导致旧绘制残留;只需在每帧开始时调用 clearRect() 清空画布即可实现平滑移动。
canvas 动画中矩形“越移越宽”并非尺寸变化,而是因未清除上一帧导致旧绘制残留;只需在每帧开始时调用 `clearrect()` 清空画布即可实现平滑移动。
在使用 HTML5
要修复该问题,关键在于实现逐帧重绘(frame-by-frame rendering):
- 清空画布:在每一帧 move() 函数开头调用 context.clearRect(0, 0, canvas.width, canvas.height),彻底擦除上一帧所有像素;
- 绘制新状态:再基于更新后的 px 值绘制当前帧的矩形;
- 持续驱动:通过 requestAnimationFrame 保证动画流畅性(通常 60fps)。
以下是修正后的核心逻辑(已整合关键优化):
let canvas = document.getElementById("canvas");
let context = canvas.getContext("2d");
let px = 0;
let directx = { right: false, left: false };
const speed = 6;
// 自适应窗口尺寸,并确保 canvas DOM 属性与 CSS 尺寸一致
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
resizeCanvas();
window.addEventListener("resize", resizeCanvas);
// 设置背景色(注意:CSS 背景仅作底色,不影响 clearRect)
canvas.style.backgroundColor = "red";
document.addEventListener("keydown", (e) => {
if (e.key === "d") {
directx.right = true;
directx.left = false;
} else if (e.key === "a") {
directx.right = false;
directx.left = true;
}
});
// 添加 keyup 事件避免按键卡死
document.addEventListener("keyup", (e) => {
if (e.key === "d" || e.key === "a") {
directx.right = false;
directx.left = false;
}
});
function move() {
// ✅ 关键步骤:清除整帧画布
context.clearRect(0, 0, canvas.width, canvas.height);
// 绘制当前帧的正方形(固定宽高:100×100)
context.fillStyle = "#007bff"; // 可选:添加颜色提升可读性
context.fillRect(px, 0, 100, 100);
// 更新位置
if (directx.right) px += speed;
if (directx.left) px -= speed;
// 边界限制(可选增强体验)
px = Math.max(0, Math.min(px, canvas.width - 100));
requestAnimationFrame(move);
}
move();
⚠️ 注意事项:
- clearRect() 的参数必须准确匹配画布实际尺寸(即 canvas.width/canvas.height,而非 clientWidth/clientHeight),否则可能残留未清除区域;
- 键盘事件需配合 keyup 释放逻辑,否则松开按键后方向标志仍为 true,导致持续移动;
- 若需响应式适配,务必监听 resize 并同步更新 canvas.width/height(仅修改 DOM 属性,不依赖 CSS 缩放);
- fillRect() 绘制的是实心矩形,若需描边或复杂图形,后续可扩展为 beginPath() + rect() + stroke() 流程。
掌握「清除→绘制→更新」这一 Canvas 动画黄金三步法,即可稳定实现任意对象的平滑位移,为更复杂的交互与游戏开发奠定坚实基础。











