使用requestAnimationFrame实现物体跳跃异常问题求助
问题分析
你的代码核心问题在于同时触发了上升和下落两个动画,而且共用了同一个time对象,导致两个动画逻辑互相干扰:
jump()函数里同时调用requestAnimationFrame(moveup)和requestAnimationFrame(movedown),这两个回调会在同一帧(或极短时间内)执行。- 你紧接着把
time.start=0,movedown执行时会把position计算为finalPosition*(1-0)=finalPosition,直接把物体放到最高处,覆盖了moveup的初始计算。 - 之后只有
movedown的逻辑在持续执行,所以看起来只有下落过程是平滑的。
修复方案
我们需要让两个动画顺序执行:等上升动画完全结束后,再启动下落动画。同时要避免共用状态导致的冲突,每个动画阶段单独管理时间状态。
修改后的完整代码:
let finalPosition = 200; // 假设最大高度是200px,你可以根据需求调整 const obj = document.getElementById('your-object'); // 替换成你的物体元素 // 上升动画函数 const moveup = (now) => { // 每个动画阶段单独初始化时间状态,避免共用冲突 const time = { start: now, total: 500 }; const animate = (currentNow) => { const elapsed = currentNow - time.start; const progress = Math.min(elapsed / time.total, 1); // 防止进度超过1 // 使用缓动函数让上升更自然(可选,比如ease-out) const easedProgress = 1 - Math.pow(1 - progress, 3); const position = easedProgress * finalPosition; obj.style.bottom = `${position}px`; if (progress < 1) { requestAnimationFrame(animate); } else { // 上升结束后启动下落动画 requestAnimationFrame(movedown); } }; animate(now); }; // 下落动画函数 const movedown = (now) => { const time = { start: now, total: 500 }; const animate = (currentNow) => { const elapsed = currentNow - time.start; const progress = Math.min(elapsed / time.total, 1); // 缓动函数让下落更自然(可选,比如ease-in) const easedProgress = Math.pow(progress, 3); const position = finalPosition * (1 - easedProgress); obj.style.bottom = `${position}px`; if (progress < 1) { requestAnimationFrame(animate); } }; animate(now); }; function jump() { // 只启动上升动画,下落动画由上升动画结束后触发 requestAnimationFrame(moveup); } document.addEventListener('keydown', jump, false);
关键修改点
- 动画顺序执行:在
moveup的动画结束(progress >=1)时,才调用requestAnimationFrame(movedown),确保上升完成后再下落。 - 独立时间状态:每个动画函数内部创建自己的
time对象,避免共用状态导致的冲突,不需要再手动重置time.start。 - 缓动函数优化(可选):添加了
ease-out(上升)和ease-in(下落)的缓动计算,让跳跃更符合真实物理效果,你可以根据需求去掉或替换其他缓动公式。 - 进度边界处理:用
Math.min(progress, 1)确保进度不会超过1,避免动画结束后位置出现异常。
额外说明
如果需要支持连续跳跃(比如用户按住按键多次触发),可以添加一个isJumping标志位,防止动画叠加:
let isJumping = false; function jump() { if (!isJumping) { isJumping = true; requestAnimationFrame(moveup); } } // 在movedown的动画结束时重置标志位 const movedown = (now) => { // ... 原有代码 if (progress < 1) { requestAnimationFrame(animate); } else { isJumping = false; } };
内容的提问来源于stack exchange,提问作者rohit_r
相关产品推荐
相关产品推荐

