如何禁用鼠标悬停时动画函数的重复触发
解决鼠标悬停触发弹跳小球动画重复执行的问题
嘿,我看了你这个弹跳小球的问题,核心痛点是鼠标移动时会反复触发triggerAnimation函数,每次触发都会创建一个新的anime.js动画实例——多个动画同时作用在同一个小球元素上,互相干扰,自然就会出现卡顿或者奇怪的bug了。
问题根源拆解
你的onmousemove事件触发频率极高(鼠标稍微一动就会触发几十次),只要鼠标位置不在小球的±20像素范围内,就会调用triggerAnimation。但每次调用都会生成全新的动画序列,旧的动画还没跑完,新的就开始修改元素的translateX/translateY/scaleX属性,元素的样式被多个动画同时操控,结果必然混乱。
解决方案:两步搞定
我给你两个关键改进点,结合起来就能彻底解决这个问题:
1. 加个「动画状态锁」,禁止同时运行多个动画
定义一个全局变量标记当前是否有动画在执行,只有当没有动画在跑的时候,才允许触发新的动画。利用anime.js的complete回调在动画结束后解锁。
2. 优化触发逻辑:只在状态变化时触发动画
原来的逻辑是「只要鼠标不在范围内就触发」,改成「当鼠标从『在范围内』切换到『不在范围内』时才触发一次」,避免鼠标持续在范围外移动时反复触发。
修改后的完整代码示例
// 新增状态变量:标记是否有动画在执行,以及上一次鼠标是否在范围内 let isAnimating = false; let wasInRange = false; let mousePos; let el; window.onmousemove = logMouseMove; function logMouseMove(e) { e = e || window.event; mousePos = e.clientX; el = document.querySelector('.circle'); const elPos = getOffset(el); // 判断当前鼠标是否在小球的±20范围内 const isInRange = mousePos >= (elPos - 20) && mousePos <= (elPos + 20); // 只有当:1. 当前没有动画在执行;2. 鼠标从「在范围内」变成「不在范围内」时,才触发动画 if (!isAnimating && wasInRange && !isInRange) { triggerAnimation(); } // 更新上一次的状态 wasInRange = isInRange; } function getOffset(el) { el = el.getBoundingClientRect(); return el.left + window.scrollX + 50; } function triggerAnimation() { // 锁上动画状态 isAnimating = true; const xValues = [100, 0, 400]; const yValues = [0, 50, 200]; const xVal = xValues[Math.floor(Math.random()*xValues.length)]; const yVal = yValues[Math.floor(Math.random()*yValues.length)]; const duration = anime({ targets: '#duration .el', translateX: [ { value: xVal, duration: 1000, delay: 500, elasticity: 0 }, { value: xVal, duration: 1000, delay: 500, elasticity: 0 } ], scaleX: [ { value: 2, duration: 100, delay: 500, easing: 'easeOutExpo' }, { value: 1, duration: 900, elasticity: 300 }, { value: 2, duration: 100, delay: 500, easing: 'easeOutExpo' }, { value: 1, duration: 900, elasticity: 300 } ], translateY: [ { value: yVal, duration: 1000, delay: 500, elasticity: 0 }, { value: yVal, duration: 1000, delay: 500, elasticity: 0 } ], // 动画结束后解锁状态,允许下一次触发 complete: () => { isAnimating = false; } }); }
改动说明
isAnimating变量确保同一时间只有一个动画在运行,彻底避免多个动画叠加干扰;wasInRange变量记录上一次鼠标的位置状态,只在用户鼠标离开小球范围的瞬间触发一次动画,大幅减少不必要的函数调用;- 动画的
complete回调负责在动画结束后重置状态,保证下次鼠标离开时还能正常触发。
这样修改后,你应该就不会再遇到卡顿或者重复触发的bug了,可以试试效果~
内容的提问来源于stack exchange,提问作者Pickle_Rick
相关产品推荐
相关产品推荐

