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

原生JavaScript实现的<li>元素鼠标悬停效果异常问题求助

鼠标悬停文字动画首次触发异常问题

我用JavaScript给三个<li>元素做鼠标悬停的字符切换动画,但首次触发时效果异常,必须反复悬停才能恢复原本的文本。

效果说明

  • 原文本:三个列表项分别显示 // ABOUT、// PROJECTS、// CONTACT
  • 首次悬停异常:动画结束后文本无法正确恢复,出现错乱
  • 正常效果(反复悬停后):鼠标悬停时字符逐个随机切换,最终恢复为原文本

HTML代码

<ul>
  <li data-value="// ABOUT"    ><a href="#" >// ABOUT    </a></li>
  <li data-value="// PROJECTS" ><a href='#' >// PROJECTS </a></li>
  <li data-value="// CONTACT" ><a href="#"  >// CONTACT  </a></li>
</ul>

原JavaScript代码

const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

let interval = null;

document.querySelectorAll("li").forEach(li => {
  li.onmouseover = event => {
    let iteration = 0;

    clearInterval(interval);

    interval = setInterval(() => {
      event.target.innerText = event.target.innerText
        .split("")
        .map((letter, index) => {
          if (index < iteration) {
            return event.target.dataset.value[index];
          }

          return letters[Math.floor(Math.random() * 26)];
        })
        .join("");

      if (iteration >= event.target.dataset.value.length) {
        clearInterval(interval);
      }

      iteration += 1 / 3;
    }, 30);
  };
});

问题原因

  1. 事件目标指向错误:event.target实际指向的是<li>内部的<a>标签,但data-value属性是绑定在<li>上的,首次获取dataset.value会失败,导致文本错乱。
  2. 共享定时器冲突:所有<li>共用同一个全局interval变量,快速切换悬停目标时,定时器会被意外清除,导致动画中断或状态异常。
  3. 文本基准逻辑错误:动画中用event.target.innerText作为修改基准,首次操作时该文本是<a>的原始内容,后续修改后基准发生变化,导致反复悬停后看似正常但逻辑存在隐患。

修复后的代码

const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

document.querySelectorAll("li").forEach(li => {
  // 每个li单独维护定时器,避免元素间干扰
  let liInterval = null;
  // 提前缓存目标文本,避免重复读取DOM属性
  const targetText = li.dataset.value.trim();

  li.addEventListener('mouseover', () => {
    let iteration = 0;
    const aTag = li.querySelector('a');

    clearInterval(liInterval);

    liInterval = setInterval(() => {
      aTag.innerText = targetText
        .split("")
        .map((letter, index) => {
          if (index < iteration) {
            return targetText[index];
          }
          return letters[Math.floor(Math.random() * 26)];
        })
        .join("");

      if (iteration >= targetText.length) {
        clearInterval(liInterval);
      }

      iteration += 1 / 3;
    }, 30);
  });

  // 鼠标离开时直接恢复原文本,优化体验
  li.addEventListener('mouseout', () => {
    clearInterval(liInterval);
    li.querySelector('a').innerText = targetText;
  });
});

修复点说明

  • 给每个<li>分配独立的定时器变量,彻底解决多元素间的定时器冲突问题。
  • 提前缓存data-value的目标文本,明确操作<li>内部的<a>标签,避免event.target指向错误的问题。
  • 增加mouseout事件监听,鼠标离开时立即恢复原文本,避免残留动画状态影响后续操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 16:37:33