You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何禁用鼠标悬停时动画函数的重复触发

解决鼠标悬停触发弹跳小球动画重复执行的问题

嘿,我看了你这个弹跳小球的问题,核心痛点是鼠标移动时会反复触发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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:51:22