手电筒照射span时停止其动画的JavaScript实现问题
问题分析
核心问题出在照射检测的触发时机:当前你可能仅在mousemove事件里判断span是否被手电筒覆盖,鼠标静止时该事件不再触发,自然不会执行停止动画的逻辑。
解决方案
- 将照射检测移入动画循环(loop函数):
不管鼠标是否移动,每帧都检测所有span是否处于手电筒范围内,确保静止时也能持续判断。 - 优化动画暂停逻辑:
给每个span添加状态标记(比如data-is-paused),避免重复触发延迟定时器;同时依托requestAnimationFrame维护动画,保证暂停/恢复状态同步。
关键代码片段
// 假设手电筒元素为#flashlight,字母span类为.letter const flashlight = document.getElementById('flashlight'); const letters = document.querySelectorAll('.letter'); // 每帧执行的照射检测逻辑 function checkFlashlightCoverage() { const flashlightRect = flashlight.getBoundingClientRect(); letters.forEach(letter => { const letterRect = letter.getBoundingClientRect(); // 判断矩形是否相交(即span被照射) const isOverlapping = !( flashlightRect.right < letterRect.left || flashlightRect.left > letterRect.right || flashlightRect.bottom < letterRect.top || flashlightRect.top > letterRect.bottom ); if (isOverlapping) { // 未标记暂停时,启动5秒延迟停止 if (!letter.dataset.isPaused) { letter.dataset.isPaused = 'true'; const timerId = setTimeout(() => { letter.style.animationPlayState = 'paused'; }, 5000); letter.dataset.timerId = timerId; } } else { // 离开照射范围,恢复动画并清除状态 if (letter.dataset.isPaused) { letter.style.animationPlayState = 'running'; clearTimeout(letter.dataset.timerId); delete letter.dataset.isPaused; delete letter.dataset.timerId; } } }); } // 把检测逻辑加入动画循环 function loop() { // 原有的手电筒跟随等动画逻辑 checkFlashlightCoverage(); // 新增持续检测 requestAnimationFrame(loop); } loop();
注意事项
- 不要依赖
mousemove做持续检测,鼠标静止时该事件不会触发; - 用
getBoundingClientRect()判断元素相交是最可靠的方式,避免坐标计算误差; - 给每个span加状态标记,防止重复创建定时器,避免动画状态混乱;
- 确保检测逻辑放在
loop函数每帧都会执行的位置,适配你基于模板修改的代码结构。
内容的提问来源于stack exchange,提问作者user22755827
相关产品推荐
相关产品推荐

