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

点击按钮动态修改环形进度条Stroke与百分比值的实现咨询

实现点击按钮动态修改环形进度条数值及状态

问题背景

作为JavaScript新手,现有一套固定数值的环形进度条代码,希望添加按钮实现点击时修改各进度条的百分比数值及对应的stroke状态。

解决方案步骤

1. 重构CSS,用CSS变量实现动态过渡

原代码依赖固定动画类控制进度,改为CSS变量+过渡效果,无需编写多个@keyframes,直接通过JS修改变量即可实现平滑动画:

  • 移除原有.circle-*类及对应@keyframes
  • 给.progressbar__svg-circle添加过渡属性和变量控制:transition: stroke-dashoffset 1s ease-in-out;、stroke-dashoffset: var(--offset, 440);

2. 添加按钮控制组

在页面顶部添加按钮容器,放置不同场景的切换按钮:

<div class="button-group">
  <button data-set="set1">数据组1</button>
  <button data-set="set2">数据组2</button>
  <button data-set="set3">数据组3</button>
</div>

3. 定义数据集合

用JS存储不同数据组,每个组对应四个进度条的百分比值:

const dataSets = {
  set1: [95, 85, 70, 8], // 原默认数据
  set2: [80, 90, 60, 25],
  set3: [90, 75, 80, 15]
};

4. 编写按钮点击逻辑

  • 获取所有进度条的circle元素和百分比文本元素
  • 给按钮绑定点击事件,根据选中的数据组计算stroke-dashoffset(公式:offset = 440 * (1 - 百分比/100))
  • 更新文本内容和circle的--offset变量

完整代码

<html>
<body>
  <style>
    * {
      box-sizing: border-box;
    }
    .button-group {
      display: flex;
      gap: 10px;
      padding: 20px;
      background-color: #0d0d0d;
      justify-content: center;
    }
    .button-group button {
      padding: 8px 16px;
      border: none;
      border-radius: 4px;
      background-color: #333;
      color: #fff;
      cursor: pointer;
      transition: background-color 0.3s;
    }
    .button-group button:hover {
      background-color: #555;
    }
    .container {
      display: flex;
      justify-content: center;
      align-items: center;
      background-color: #0d0d0d;
      width:700px;
      height:220px;
    }
    .container__progressbars {
      display: flex;
      justify-content: flex-start;
      align-items: center;
      flex-wrap: nowrap;
      min-width: 170px;
      width: 100%;
      min-height: 100%;
    }
    .progressbar {
      position: relative;
      width: 170px;
      height: 270px;
      transform: rotate(-90deg);
    }
    .progressbar__svg {
      position: relative;
      width: 100%;
      height: 100%;
    }
    .progressbar__svg-circle {
      width: 100%;
      height: 100%;
      fill: none;
      stroke-width: 10;
      stroke-dasharray: 440;
      stroke-dashoffset: var(--offset, 440);
      stroke: #fff;
      stroke-linecap: round;
      transform: translate(3px, 3px);
      transition: stroke-dashoffset 1s ease-in-out;
    }
    .shadow-npd {
      filter: drop-shadow(0 0 5px #f63);
    }
    .shadow-business-con {
      filter: drop-shadow(0 0 5px #3bf);
    }
    .shadow-capex {
      filter: drop-shadow(0 0 5px #f3f);
    }
    .shadow-child-part-inv {
      filter: drop-shadow(0 0 5px #ff3);
    }
    .progressbar__text {
      position: absolute;
      top: 50%;
      left: 50%;
      padding: 0.25em 0.5em;
      color: #fff;
      font-family: Arial, Helvetica, sans-serif;
      border-radius: 0.25em;
      transform: translate(-10%, -110%) rotate(10deg);
    }
    .progressbar__topic {
      position: absolute;
      top: 50%;
      left: 50%;
      color: #fff;
      font-family: Arial, Helvetica, sans-serif;
      transform: translate(-50%, 50%) rotate(90deg);
      width: 120px;
      text-align: center;
    }
  </style>

  <div class="button-group">
    <button data-set="set1">数据组1</button>
    <button data-set="set2">数据组2</button>
    <button data-set="set3">数据组3</button>
  </div>

  <div class="container">
    <div class="container__progressbars">
      <div class="progressbar">
        <svg class="progressbar__svg">
          <circle cx="100" cy="60" r="55" class="progressbar__svg-circle shadow-npd" style="--offset: 22"></circle>
        </svg>
        <span class="progressbar__text shadow-npd">95%</span>
        <span class="progressbar__topic shadow-npd">NPD Revenue</span>
      </div>

      <div class="progressbar">
        <svg class="progressbar__svg">
          <circle cx="100" cy="60" r="55" class="progressbar__svg-circle shadow-business-con" style="--offset: 66"></circle>
        </svg>
        <span class="progressbar__text shadow-business-con">85%</span>
        <span class="progressbar__topic shadow-business-con">Business Conversion</span>
      </div>

      <div class="progressbar">
        <svg class="progressbar__svg">
          <circle cx="100" cy="60" r="55" class="progressbar__svg-circle shadow-capex" style="--offset: 132"></circle>
        </svg>
        <span class="progressbar__text shadow-capex">70%</span>
        <span class="progressbar__topic shadow-capex">Capex</span>
      </div>

      <div class="progressbar">
        <svg class="progressbar__svg">
          <circle cx="100" cy="60" r="55" class="progressbar__svg-circle shadow-child-part-inv" style="--offset: 404.8"></circle>
        </svg>
        <span class="progressbar__text shadow-child-part-inv">8%</span>
        <span class="progressbar__topic shadow-child-part-inv">Child Part Inventory</span>
      </div>
    </div>
  </div>

  <script>
    // 定义不同的数据组
    const dataSets = {
      set1: [95, 85, 70, 8],
      set2: [80, 90, 60, 25],
      set3: [90, 75, 80, 15]
    };

    // 获取元素
    const circles = document.querySelectorAll('.progressbar__svg-circle');
    const textElements = document.querySelectorAll('.progressbar__text');
    const buttons = document.querySelectorAll('.button-group button');

    // 绑定点击事件
    buttons.forEach(button => {
      button.addEventListener('click', () => {
        const setKey = button.dataset.set;
        const data = dataSets[setKey];
        
        data.forEach((percent, index) => {
          // 计算对应的stroke-dashoffset:总长度440,offset=440-已完成长度
          const offset = 440 * (1 - percent / 100);
          // 更新circle的offset变量
          circles[index].style.setProperty('--offset', offset);
          // 更新百分比文本
          textElements[index].textContent = `${percent}%`;
        });
      });
    });
  </script>
</body>
</html>

关键说明

  • CSS变量--offset替代固定动画,配合transition实现平滑过渡
  • 数据组可自由扩展,添加新按钮和对应数据即可
  • 百分比转stroke-dashoffset的公式保证进度显示准确,核心逻辑为总长度减去已完成长度

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 07:19:54