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

如何用JavaScript实现<li>悬停启动CSS动画、切换时停止重置

解决鼠标悬停控制多元素CSS动画的启动与重置问题

我来帮你搞定这个需求——当鼠标悬停某个<li>时启动四个圆形元素的CSS动画,切换到其他<li>时停止并重置之前的动画。下面是完整的可实现方案:

调整后的HTML结构

首先给每个导航项加上标识类,方便后续JS定位,同时确保每个<li>里的动画元素结构清晰:

<nav class="strokes">
  <ul>
    <li class="nav-item">
      <div class="circle one"></div>
      <div class="circle2 two"></div>
      <div class="circle3 three"></div>
      <div class="circle4 four"></div>
    </li>
    <li class="nav-item">
      <!-- 第二个li的动画元素,结构和第一个保持一致即可 -->
      <div class="circle five"></div>
      <div class="circle2 six"></div>
      <div class="circle3 seven"></div>
      <div class="circle4 eight"></div>
    </li>
  </ul>
</nav>

CSS 动画与样式定义

我们用类来触发动画,同时定义重置状态的样式,确保动画能彻底回到初始状态:

/* 基础圆形样式,对应动画初始状态 */
.circle, .circle2, .circle3, .circle4 {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  margin: 8px 0;
  background-color: #2c3e50;
  opacity: 0;
  transform: translateX(30px);
  transition: none; /* 避免和动画冲突 */
}

/* 动画触发类:给元素添加这个类就会启动动画 */
.animate-circle {
  animation: slideInRight 0.6s forwards;
}
/* 给四个圆形设置不同的动画延迟,形成依次出现的效果 */
.animate-circle.one { animation-delay: 0s; }
.animate-circle.two { animation-delay: 0.15s; }
.animate-circle.three { animation-delay: 0.3s; }
.animate-circle.four { animation-delay: 0.45s; }

/* 动画关键帧(可以根据你的需求修改动画效果) */
@keyframes slideInRight {
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

/* 重置类:强制元素回到初始状态 */
.reset-circle {
  animation: none !important;
  opacity: 0;
  transform: translateX(30px);
}

JavaScript 核心逻辑

通过监听鼠标事件,控制动画的启动和重置,核心是处理切换时的重置逻辑:

// 获取所有导航项
const navItems = document.querySelectorAll('.nav-item');

// 给每个导航项绑定鼠标事件
navItems.forEach(currentItem => {
  // 鼠标悬停时:启动当前项的动画,重置其他项的动画
  currentItem.addEventListener('mouseover', () => {
    // 遍历所有导航项,重置非当前项的动画
    navItems.forEach(item => {
      if (item !== currentItem) {
        const circles = item.querySelectorAll('.circle, .circle2, .circle3, .circle4');
        circles.forEach(circle => {
          // 先移除动画类,添加重置类
          circle.classList.remove('animate-circle');
          circle.classList.add('reset-circle');
          // 强制触发浏览器重绘,确保重置生效(关键步骤)
          void circle.offsetWidth;
          // 移除重置类,为下次动画做准备
          circle.classList.remove('reset-circle');
        });
      }
    });

    // 启动当前导航项的动画
    const currentCircles = currentItem.querySelectorAll('.circle, .circle2, .circle3, .circle4');
    currentCircles.forEach(circle => {
      circle.classList.add('animate-circle');
    });
  });

  // 可选:鼠标离开当前项时,也重置自身的动画
  currentItem.addEventListener('mouseout', () => {
    const currentCircles = currentItem.querySelectorAll('.circle, .circle2, .circle3, .circle4');
    currentCircles.forEach(circle => {
      circle.classList.remove('animate-circle');
      circle.classList.add('reset-circle');
      void circle.offsetWidth;
      circle.classList.remove('reset-circle');
    });
  });
});

关键细节解释

  1. 动画重置的核心:void circle.offsetWidth这一行是为了强制浏览器重新计算元素尺寸,触发重绘,否则直接移除动画类可能不会让元素立刻回到初始状态,导致下次动画无法正常播放。
  2. 动画触发方式:通过添加/移除animate-circle类来控制动画的启动,这种方式比直接操作style属性更灵活,也符合CSS与JS分离的原则。
  3. 多元素序列动画:通过给每个圆形元素设置不同的animation-delay,实现依次出现的连贯效果,你可以根据需求调整延迟时间。

这个方案完美匹配你的需求:鼠标悬停任意<li>时,该<li>内的四个圆形元素依次启动动画;切换到其他<li>时,之前的动画会立刻停止并重置,新的动画随即启动。

内容的提问来源于stack exchange,提问作者user3404273

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:38:55