点击按钮动态修改环形进度条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
相关产品推荐
相关产品推荐

