为什么新增的if语句会导致我的JavaScript骑士跳岩游戏功能失效
问题原因分析
- 无限死循环阻塞主线程:你代码中的
while (falseVar == false)循环内没有任何修改falseVar值的逻辑,循环会无限执行,完全占满JS单线程,直接导致页面崩溃。你想要的动画循环效果不能用同步while循环实现,需要靠异步的动画结束回调触发下一次动画。 - 冗余代码问题:三个动画函数逻辑高度重复,且定义在循环内部,每次循环都会重复创建函数,产生不必要的性能开销。
- 潜在样式冲突风险:添加新的动画类之前没有清除旧的动画类,多个类叠加可能导致动画表现异常。
修复后的代码参考
CSS代码
#rock { height: 50px; width: 50px; position: relative; top: 122px; left: 550px; background-image: url("http://pixelartmaker-data-78746291193.nyc3.digitaloceanspaces.com/image/da268f06e621b21.png"); background-size: cover; } .rockAnimationFast { animation: rockAnimationFast 0.75s linear forwards; } .rockAnimationMedium { animation: rockAnimationMedium 1s linear forwards; } .rockAnimationSlow { animation: rockAnimationSlow 1.5s linear forwards; } @keyframes rockAnimationFast { 0%{left: 500px;} 100%{left: -50px;} } @keyframes rockAnimationMedium { 0%{left: 500px;} 100%{left: -50px;} } @keyframes rockAnimationSlow { 0%{left: 500px;} 100%{left: -50px;} }
JavaScript代码
// 缓存岩石DOM节点,避免每次查询DOM const rock = document.getElementById("rock"); // 动画配置统一管理 const animationConfigs = [ { className: 'rockAnimationFast', duration: 750, weight: 4 }, // 权重4,对应0-3共4个随机值 { className: 'rockAnimationMedium', duration: 1000, weight: 4 }, // 权重4,对应4-7共4个随机值 { className: 'rockAnimationSlow', duration: 1500, weight: 2 } // 权重2,对应8-9共2个随机值 ] let dead = false; // 单次岩石动画逻辑 function playRockAnimation() { if (dead) return; // 清除所有旧的动画类 rock.classList.remove('rockAnimationFast', 'rockAnimationMedium', 'rockAnimationSlow'); // 强制回流,保证移除类之后重新添加类能触发动画重放 void rock.offsetWidth; // 随机选择动画 const randRockSpeed = Math.floor(Math.random() * 10); let selectedConfig; if (randRockSpeed <=3) { selectedConfig = animationConfigs[0]; } else if (randRockSpeed <=7) { selectedConfig = animationConfigs[1]; } else { selectedConfig = animationConfigs[2]; } // 添加动画类 rock.classList.add(selectedConfig.className); // 动画结束后触发下一次动画 setTimeout(() => { playRockAnimation(); }, selectedConfig.duration); } function play() { dead = false; playRockAnimation(); } // 如果需要终止游戏,调用这个方法即可 function stopGame() { dead = true; }
关键修改说明
- 去掉了同步死循环,改用
setTimeout在每次动画结束后异步触发下一次动画,不会阻塞主线程 - 提前缓存了岩石DOM节点,避免每次都查询DOM提升性能
- 每次添加动画类前先清除所有旧动画类,加
void rock.offsetWidth触发浏览器回流,保证动画可以重复触发 - 所有动画配置统一管理,后续要调整速度、概率都可以直接修改配置数组,不用修改逻辑代码
内容的提问来源于stack exchange,提问作者flyingchicken
相关产品推荐
相关产品推荐

