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

JS多元素data属性计数实现 各元素独立停止在对应data-num值

问题描述

页面存在多个带.number类的div元素,每个元素配置了取值互不相同的data-num自定义属性,需要通过JavaScript实现数字从0开始递增的计数动画,最终将计数结果输出到对应div中,且每个元素计数到自身data-num对应的数值时自动停止。
原代码运行时出现异常:计数器无法在对应元素的目标值处停止,会无限持续递增,所有元素的计数状态互相干扰。

原实现代码

JavaScript 代码

const numbers = document.querySelectorAll(".number");
console.log(numbers);
let counter = 0;
setInterval(() => {
 numbers.forEach((number) => {
        if(counter === number.dataset.num){
            clearInterval();
        }else{
            counter += 1;
            number.innerHTML = counter + "%";
        }
    })
}, 20);

HTML 代码

<div class="skill-level position-absolute">
  <div class="outer">
    <div class="inner d-flex align-items-center justify-content-center">
      <div class="number" data-num="95"></div>
    </div>
  </div>
  <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="160px" height="160px">
    <defs>
      <linearGradient id="GradientColor">
        <stop offset="0%" stop-color="#e91e63" />
        <stop offset="100%" stop-color="#673ab7" />
      </linearGradient>
    </defs>
    <circle cx="80" cy="80" r="70" stroke-linecap="round" />
  </svg>
</div>
<div class="skill-level position-absolute">
  <div class="outer">
    <div class="inner d-flex align-items-center justify-content-center">
      <div class="number" data-num="70"></div>
    </div>
  </div>
  <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="160px" height="160px">
    <defs>
      <linearGradient id="GradientColor">
        <stop offset="0%" stop-color="#e91e63" />
        <stop offset="100%" stop-color="#673ab7" />
      </linearGradient>
    </defs>
    <circle cx="80" cy="80" r="70" stroke-linecap="round" />
  </svg>
</div>
故障原因
  • 全局仅声明了一个counter变量,所有计数元素共享同一个计数状态,无法匹配每个元素独立的目标值
  • clearInterval()调用时没有传入定时器返回的唯一ID,无法终止正在运行的定时器
  • 遍历逻辑存在缺陷:每次定时器触发时会给所有元素同步累加同一个全局计数器,即便小目标值的元素达到阈值,全局计数器仍会持续累加,导致计数无限上涨
修复实现

核心思路是给每个.number元素绑定独立的计数变量、独立的定时器实例,计数状态互不干扰,计数到自身目标值时清除对应定时器即可。修复后的JavaScript代码如下:

const numbers = document.querySelectorAll(".number");
numbers.forEach(number => {
  // 每个元素维护独立的计数初始值
  let counter = 0;
  // 读取当前元素的目标计数,dataset返回字符串类型,显式转为数字
  const target = Number(number.dataset.num);
  // 为每个元素创建独立定时器,保存定时器ID用于后续清除
  const countTimer = setInterval(() => {
    if (counter >= target) {
      // 达到目标值,清除当前元素对应的定时器
      clearInterval(countTimer);
      // 兜底确保最终显示值和目标值完全一致
      number.textContent = `${target}%`;
      return;
    }
    counter++;
    number.textContent = `${counter}%`;
  }, 20);
})

上述实现无需修改原有HTML结构,每个元素的计数动画独立运行,到达自身目标值后自动停止,不会出现无限递增、计数互相干扰的问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 13:36:15