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

如何将forEach替换为Map并优化进度条函数实现复用与简洁化?

改造进度条函数:替换forEach为Map、实现复用与代码优化

一、用Map替代forEach的逻辑

原代码里forEach只是单纯遍历执行操作,Map的优势是遍历同时返回新数组存储结果,刚好可以用来生成每个进度条的定时器引用数组,不用提前声明空数组再填充,逻辑更紧凑。

二、优化后的可复用代码

直接上改造完成的代码,关键改动都加了注释:

function initProgressBars(numberSelector, circleSelector) {
  // 将DOM选择器返回的NodeList转为数组,方便使用数组方法
  const numbers = Array.from(document.querySelectorAll(numberSelector));
  const svgCircles = Array.from(document.querySelectorAll(circleSelector));
  
  // 用Map遍历每个数字元素,返回对应的定时器引用,直接生成intervals数组
  const intervals = numbers.map((number, index) => {
    const target = +number.dataset.num; // 用+号快速完成字符串转数字,替代parseInt
    let counter = 0;
    // 提前计算目标strokeDashoffset,避免定时器循环内重复计算浪费性能
    const targetOffset = Math.floor(472 - 440 * (target / 100));
    
    return setInterval(() => {
      if (counter === target) {
        clearInterval(intervals[index]); // 修复原代码中clearInterval用错变量的问题
        return;
      }
      counter++;
      number.textContent = `${counter}%`;
      svgCircles[index].style.strokeDashoffset = targetOffset;
    }, 20);
  });

  // 返回定时器数组,方便外部需要时手动清除(可选)
  return intervals;
}

// 调用示例:在任意位置调用,传入对应选择器即可
// const myProgressIntervals = initProgressBars('.number', 'svg circle');

关键改动说明

  • 替换forEach为Map:用numbers.map()替代forEach,遍历过程中直接生成定时器引用数组,省去了原代码里提前声明空intervals数组的步骤,逻辑更顺畅。
  • 实现完全复用:函数接收两个选择器参数,不管页面中进度条处于什么位置,只要传入对应.number和svg circle的选择器,就能直接调用,避免全局变量污染。
  • 代码精简优化:
    • 用Array.from转换NodeList为数组,方便使用数组原生方法;
    • 用+号替代parseInt/parseFloat,快速完成类型转换,代码更简洁;
    • 提前计算strokeDashoffset的目标值,避免定时器循环内重复计算,提升性能;
    • 修复原代码中clearInterval(counters[index])的错误,改为清除对应的定时器引用;
    • 将计数器counter改为局部变量,不再依赖全局counters数组,代码更干净。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 09:05:20