如何基于时间间隔实现用户按键控制的网页图片平滑移动效果
问题根源
- 代码逻辑错误:
setInterval的第一个参数传入了addEventListener的返回值,等于每100毫秒就重复注册一次keydown事件监听器,最终会有几百个重复的监听器同时执行,不仅卡顿还会造成性能泄漏 - 依赖
keydown事件触发位移:系统原生的keydown事件有默认的首触发延迟,按住按键后会先等几百毫秒才会连续触发,这是卡顿的核心原因 - 没有使用浏览器原生的帧动画API:
setInterval的计时精度低,而且不会和浏览器的渲染节奏对齐,容易出现掉帧
修复方案
核心逻辑是:用keydown和keyup事件记录当前按键状态,再用requestAnimationFrame(和浏览器渲染帧对齐的API)每帧更新位移,即可实现丝滑的移动效果。
修复后完整代码:
<!DOCTYPE html> <html> <head> <style> #avaOne {position: absolute; left: 0px; width: 50px;} </style> </head> <body> <img id="avaOne" src="avaOne.png"/> </body> <script> var xPos = 300; // 按键状态标记,记录当前是否按住左右键 var isLeftPressed = false; var isRightPressed = false; // 移动速度:每帧移动的像素值,数值越大移动越快 var moveSpeed = 2; // 监听按键按下,更新状态 window.addEventListener("keydown", function(event) { if (event.keyCode == 37) { isLeftPressed = true; } else if (event.keyCode == 39) { isRightPressed = true; } }); // 监听按键松开,更新状态 window.addEventListener("keyup", function(event) { if (event.keyCode == 37) { isLeftPressed = false; } else if (event.keyCode == 39) { isRightPressed = false; } }); // 帧更新函数,和浏览器渲染节奏对齐,每秒执行约60次 function updatePosition() { if (isLeftPressed) { xPos -= moveSpeed; } if (isRightPressed) { xPos += moveSpeed; } document.getElementById("avaOne").style.left = xPos + "px"; // 递归调用,持续更新 requestAnimationFrame(updatePosition); } // 启动帧更新 requestAnimationFrame(updatePosition); </script> </html>
额外优化建议
如果要进一步提升流畅度,可以把修改left属性改成修改transform,不会触发页面重排,性能更高:
// 把原来的style.left赋值换成下面的代码 document.getElementById("avaOne").style.transform = `translateX(${xPos}px)`; // 对应的css里可以删掉left:0px的初始值,xPos初始值对应位移距离即可
内容的提问来源于stack exchange,提问作者user14204644
相关产品推荐
相关产品推荐

