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

如何在环形进度条统计模块中支持浮点数值?

如何在环形进度条统计模块中支持浮点数值?

嘿,我一眼就瞅出问题所在啦!你当前的代码里用progressStartValue++每次让数值加1,这对整数没问题,但碰到99.9这种小数时,这个变量永远只会是整数,根本到不了目标的浮点值,再加上用==判断浮点数相等(本身就容易有精度坑),定时器自然停不下来啦。咱们来改几处就能解决:

核心问题分析

  • 整数递增逻辑:progressStartValue++只能生成整数,永远追不上99.9这种浮点目标值;
  • 浮点数相等判断:直接用==比较浮点数,会因为JS的浮点精度问题永远无法匹配(比如0.1+0.2≠0.3);
  • 数值显示精度:浮点运算可能产生多余的小数位,影响显示效果。

修改方案
把定时器里的代码改成下面这样,我给你标了关键修改点:

let progress = setInterval(() => {
  // 1. 改成每次增加0.1,适配浮点数值(步长可根据动画速度调整)
  progressStartValue += 0.1;
  // 2. 格式化显示数值,避免精度问题导致的奇怪小数位
  // 这里判断如果目标是整数就显示整数,否则显示一位小数
  const displayValue = Number.isInteger(progressEndValue) 
    ? progressStartValue.toFixed(0) 
    : progressStartValue.toFixed(1);
  progressValue.textContent = displayValue;
  
  circularProgress.style.background = `conic-gradient(#099bf0, #7cbf3d,#00b3cf, #1f58f2, #5618d4 ${progressStartValue * 3.6}deg, #EAEAEC 0deg)`;

  // 3. 改用范围判断,避免浮点数相等的精度坑
  if (progressStartValue >= progressEndValue - 0.05) {
    // 4. 最后强制设置为目标值,保证显示和进度条完全准确
    progressValue.textContent = Number.isInteger(progressEndValue) 
      ? progressEndValue.toFixed(0) 
      : progressEndValue.toFixed(1);
    circularProgress.style.background = `conic-gradient(#099bf0, #7cbf3d,#00b3cf, #1f58f2, #5618d4 ${progressEndValue * 3.6}deg, #EAEAEC 0deg)`;
    clearInterval(progress);
  }
}, speed);

额外说明

  • 步长调整:你可以修改0.1这个步长,比如改成0.05动画会更平滑,但动画时长会变长;改成0.2则更快,根据需求调整就行;
  • 为什么parseInt没用:parseInt(99.9)会直接把小数转成99,虽然能让定时器停止,但丢失了你想要保留的小数信息,所以不是正确的解决方案;
  • 精度误差处理:判断时用progressStartValue >= progressEndValue - 0.05是给浮点运算留了一点误差空间,确保能触发停止逻辑。

修改后的完整JS代码

const statContainer = document.querySelectorAll(".stat-container");

const options = {
  root: null,
  threshold: 0,
  rootMargin: "-150px"
};

const observer = new IntersectionObserver(function(entries, observer) {
  entries.forEach(entry => {
    if (!entry.isIntersecting) {
      return;
    }

    let container = entry.target;
    let circularProgress = container.querySelector(".circular-progress"),
        progressValue = container.querySelector(".progress-value");

    let progressEndValue = parseFloat(progressValue.innerText),
        speed = 1;
    // 初始值设为0.0更清晰,JS数字类型不影响,但语义更明确
    let progressStartValue = 0.0;

    console.log(progressEndValue);

    let progress = setInterval(() => {
      progressStartValue += 0.1;
      const displayValue = Number.isInteger(progressEndValue) 
        ? progressStartValue.toFixed(0) 
        : progressStartValue.toFixed(1);
      progressValue.textContent = displayValue;
      
      circularProgress.style.background = `conic-gradient(#099bf0, #7cbf3d,#00b3cf, #1f58f2, #5618d4 ${progressStartValue * 3.6}deg, #EAEAEC 0deg)`;

      if (progressStartValue >= progressEndValue - 0.05) {
        progressValue.textContent = Number.isInteger(progressEndValue) 
          ? progressEndValue.toFixed(0) 
          : progressEndValue.toFixed(1);
        circularProgress.style.background = `conic-gradient(#099bf0, #7cbf3d,#00b3cf, #1f58f2, #5618d4 ${progressEndValue * 3.6}deg, #EAEAEC 0deg)`;
        clearInterval(progress);
      }
    }, speed);

    observer.unobserve(entry.target);
  })
}, options);

statContainer.forEach(stat => {
  observer.observe(stat);
});

原始CSS(无需修改)

/* Start of Stat Styling */
.stat-container {
  align-items: center;
  display: flex;
  flex-direction: column;
  row-gap: 30px;
}

/* Controls Color of the Ring */
.circular-progress {
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  height: 200px;
  width: 200px;
  border-radius: 50%;
  background: conic-gradient(#5618d4, #1f58f2, #099bf0, #00b3cf, #7cbf3d 0deg, #EAEAEC 0deg);
}

/* Controls Color Inside of the Ring */
.circular-progress::before {
  content: "";
  position: absolute;
  height: 180px;
  width: 180px;
  border-radius: 50%;
  background-color: #FFFFFF;
}

.progress-value {
  background: -webkit-linear-gradient(360deg, #5618D4, #1F58F2, #099BF0);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  position: relative;
  font-size: 3.875rem;
  line-height: 3.875rem;
}

.progress-value:after {
  content: "%";
}

.text {
  color: #060F42;
  font-size: 1.5rem;
  line-height: 2.125rem;
  letter-spacing: -0.24px;
  max-width: 582px;
  width: 100%;
  text-align: center;
}
/* End of Stat Styling */

原始HTML(无需修改)

<div>
  <div class="stat-container">
    <div class="circular-progress">
      <span class="progress-value">99.9</span>
    </div>
    <span class="text">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor.</span>
  </div>
  <div class="stat-container">
    <div class="circular-progress">
      <span class="progress-value">70</span>
    </div>
    <span class="text">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor.</span>
  </div>
  <div class="stat-container">
    <div class="circular-progress">
      <span class="progress-value">99</span>
    </div>
    <span class="text">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor.</span>
  </div>
</div>

这样不管是整数还是小数,进度条都能正常走完并准确停止啦!

备注:内容来源于stack exchange,提问作者rnkwill

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.21 11:18:07