SVG 圆形进度条:基于指定数值动态完成填充的完整实现

轻强大大_4747

轻强大大_4747

2026-10-21

120人浏览

原创

SVG 圆形进度条:基于指定数值动态完成填充的完整实现

本文详解如何使用 SVG + CSS + JavaScript 构建可精确控制完成度的圆形进度条,支持自定义目标值、颜色与动画,并修复原代码中 stroke-dashoffset 计算错误、DOM 查询范围混乱及旋转方向不一致等核心问题。

本文详解如何使用 svg + css + javascript 构建可精确控制完成度的圆形进度条,支持自定义目标值、颜色与动画,并修复原代码中 `stroke-dashoffset` 计算错误、dom 查询范围混乱及旋转方向不一致等核心问题。

要实现一个真正按设定数值(如 75/100 或 135/200)精准填充的 SVG 圆形进度条,关键在于正确理解 SVG 圆形路径的绘制原理与 stroke-dasharray / stroke-dashoffset 的协同机制。

✅ 核心原理说明

  • SVG 圆的周长 = 2 × π × r。示例中 r = 135 → 周长 ≈ 2 × 3.1416 × 135 ≈ 848.23,因此 stroke-dasharray: 848 是合理近似。
  • stroke-dasharray: 848 表示“实线长度 = 848,间隙 = 0”,即整圈为单段实线。
  • stroke-dashoffset 控制该实线起始位置的偏移量:值越大,未填充部分越长;当 offset = 0 时,圆完全填满(从起点开始画满整圈);当 offset = 848 时,圆完全为空(起点被偏移到终点,无可见绘制)。
  • 因此,填充百分比 = (targetDegree / maxDegree) × 100%,对应 offset = circumference × (1 − percentage)。

⚠️ 原代码错误点:

  • percentage = degree / targetDegree 后误用 progressCalc = 848 - (848 * targetDegree) / 100(恒定计算,未随 degree 变化);
  • 使用 conic-gradient 覆盖 SVG 原生描边,失去矢量精度与性能优势;
  • document.querySelector('.text') 全局查询,导致多个进度条时仅操作第一个;
  • svg { transform: rotate(90deg) } 与动画方向不匹配,应统一为 -90deg 实现顺时针填充。

✅ 正确实现代码(含结构优化)



  <meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>SVG Circular Progress Bar</title><style>
    body {
      margin: 0;
      height: 100vh;
      background: #191932;
      display: flex;
      justify-content: center;
      align-items: center;
      font-family: 'Poppins', sans-serif;
    }
    .progress-container {
      position: relative;
      width: 400px;
      height: 400px;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .progress-ring {
      transform: rotate(-90deg); /* 关键:使0°在顶部,顺时针增长 */
    }
    .progress-ring circle {
      fill: none;
      stroke-linecap: round;
    }
    .progress-ring .bg-circle {
      stroke: #f0f8ff;
      stroke-width: 12px;
    }
    .progress-ring .fill-circle {
      stroke: #0b60e9;
      stroke-width: 16px;
      stroke-dasharray: 848; /* 周长近似值 */
      stroke-dashoffset: 848; /* 初始全空 */
      transition: stroke-dashoffset 0.3s ease-out; /* 平滑动画 */
    }
    .progress-text {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      text-align: center;
      color: #4e5bcd;
      font-size: 60px;
      font-weight: 500;
      line-height: 1;
    }
    .progress-text span {
      display: block;
      font-size: 14px;
      margin-top: 8px;
      color: #4e5bcd;
    }
  </style><div class="progress-container">
    <svg class="progress-ring" data-degree="75" data-color="#0b60e9" width="300" height="300" viewbox="0 0 300 300"><circle class="bg-circle" cx="150" cy="150" r="135"></circle><circle class="fill-circle" cx="150" cy="150" r="135"></circle></svg><div class="progress-text">
      <span class="progress-value">0</span>
      <span>Completed</span>
    </div>
  </div>

  <script>
    document.addEventListener('DOMContentLoaded', () => {
      const progressBars = document.querySelectorAll('.progress-ring');
      const circumference = 848; // 2 * Math.PI * 135 ≈ 848.23

      progressBars.forEach(bar => {
        const targetDegree = parseInt(bar.getAttribute('data-degree')) || 0;
        const color = bar.getAttribute('data-color') || '#0b60e9';
        const fillCircle = bar.querySelector('.fill-circle');
        const valueEl = bar.closest('.progress-container').querySelector('.progress-value');

        // 初始化样式
        fillCircle.style.stroke = color;

        // 动态更新函数(支持任意目标值,不限于100)
        const animateProgress = () => {
          let current = 0;
          const increment = targetDegree > 100 ? Math.ceil(targetDegree / 100) : 1;
          const duration = 1000;
          const steps = 100;
          const interval = Math.floor(duration / steps);

          const timer = setInterval(() => {
            current += increment;
            if (current >= targetDegree) {
              current = targetDegree;
              clearInterval(timer);
            }

            const percentage = current / targetDegree;
            const offset = circumference - (circumference * percentage);
            fillCircle.style.strokeDashoffset = offset;
            valueEl.textContent = Math.round(current);
          }, interval);
        };

        animateProgress();
      });
    });
  </script>

? 关键改进点总结

  • 精准数学映射:offset = circumference × (1 − current/target) 确保任意 targetDegree(如 135、200)均可准确填充;
  • 模块化 DOM 操作:每个进度条独立查找其子元素(.fill-circle, .progress-value),避免多实例冲突;
  • CSS 驱动平滑过渡:transition: stroke-dashoffset 0.3s ease-out 替代 JS 逐帧设置,性能更优;
  • 语义化结构:分离 SVG 容器(.progress-container)、环形图(.progress-ring)与文本层,便于复用与响应式扩展;
  • 健壮性增强:添加 || 0 和 || '#0b60e9' 默认值,防止属性缺失报错。

? 进阶提示:若需支持「百分比输入」(如 data-degree="75%")或「双刻度显示」(如 75/100),可在 valueEl.textContent 中扩展逻辑,例如:

const maxVal = parseInt(bar.getAttribute('data-max')) || 100;
valueEl.innerHTML = `${Math.round(current)}<span>/${maxVal}</span>`;

通过以上实现,你将获得一个轻量、可配置、高性能且符合 W3C 标准的 SVG 圆形进度条,完美适配数据仪表盘、加载状态、技能展示等多种场景。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
html版权符号
html版权符号

html版权符号是“©”,可以在html源文件中直接输入或者从word中复制粘贴过来,php中文网还为大家带来html的相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.14

6395

7

html在线编辑器
html在线编辑器

html在线编辑器是用于在线编辑的工具,编辑的内容是基于HTML的文档。它经常被应用于留言板留言、论坛发贴、Blog编写日志或等需要用户输入普通HTML的地方,是Web应用的常用模块之一。php中文网为大家带来了html在线编辑器的相关教程、以及相关文章等内容,供大家免费下载使用。

2023.06.21

3572

4

html网页制作
html网页制作

html网页制作是指使用超文本标记语言来设计和创建网页的过程,html是一种标记语言,它使用标记来描述文档结构和语义,并定义了网页中的各种元素和内容的呈现方式。本专题为大家提供html网页制作的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.31

3250

5

html空格
html空格

html空格是一种用于在网页中添加间隔和对齐文本的特殊字符,被用于在网页中插入额外的空间,以改变元素之间的排列和对齐方式。本专题为大家提供html空格的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.01

3259

5

html是什么
html是什么

HTML是一种标准标记语言,用于创建和呈现网页的结构和内容,是互联网发展的基石,为网页开发提供了丰富的功能和灵活性。本专题为大家提供html相关的各种文章、以及下载和课程。

2023.08.11

4959

6

html字体大小怎么设置
html字体大小怎么设置

在网页设计中,字体大小的选择是至关重要的。合理的字体大小不仅可以提升网页的可读性,还能够影响用户对网页整体布局的感知。php中文网将介绍一些常用的方法和技巧,帮助您在HTML中设置合适的字体大小。

2023.08.11

3201

3

html转txt
html转txt

html转txt的方法有使用文本编辑器、使用在线转换工具和使用Python编程。本专题为大家提供html转txt相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.31

3009

3

html文本框代码怎么写
html文本框代码怎么写

html文本框代码:1、单行文本框【<input type="text" style="height:..;width:..;" />】;2、多行文本框【textarea style=";height:;"></textare】。

2023.09.01

2648

6

HTML嵌入CSS样式的方法
HTML嵌入CSS样式的方法

HTML嵌入CSS样式的方法有内联样式、内部样式表和外部样式表。本专题为大家提供CSS样式相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.20

2728

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.7万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.9万人学习