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

如何实现点击单选按钮累加百分比更新进度条动画

核心问题定位

你原来的代码有两个致命缺陷导致效果不符合预期:

  • 所有进度动画全是硬编码的CSS关键帧,动画起始值、结束值都是写死的固定值,根本不会读取进度条当前的实际宽度。每次新增动画class都会强制进度条从预设的起始值开始播放,必然出现重置跳变,根本做不到基于当前值的增减。
  • 事件绑定逻辑完全混乱:全局注册click事件,每次页面任意位置点击都会重复执行domReady回调,给单选按钮重复绑定click事件,点的次数越多绑定的处理器越多,且动画class只增不减,逻辑完全失控。

修复方案

实现思路

彻底抛弃硬编码关键帧的方案,改用「JS动态计算总进度 + CSS transition平滑过渡」的模式:

  1. 给每个单选按钮自定义data-progress属性,存储当前选项对应的进度权重
  2. 每次选选项时,遍历所有已选中的单选按钮,累加权重得到总进度值
  3. 直接给进度条设置新的宽度值,靠CSS的transition属性自动从当前宽度平滑过渡到目标宽度,从根源上避免跳变重置
  4. 事件只在DOM加载完成后绑定一次,没有重复绑定、冗余class的问题,不需要刷新页面,任意顺序点击都能正常响应。

完整修改后代码

CSS部分

删除所有硬编码的.progress-value-xx类和对应的@keyframes动画,只保留基础样式和过渡属性:

body{
  padding:12px;
}

.col-6 label{
  border:1px solid #333;
  padding: 8px 12px;
  border-radius: 4px;
  cursor: pointer;
  display: block;
  margin-bottom: 8px;
}
.col-6 input[type=radio]:checked + label{
  border:2px solid #0d6efd;
}

.progress {
  background: #e9ecef;
  justify-content: flex-start;
  border-radius: 100px;
  align-items: center;
  position: relative;
  display: flex;
  height: 10px;
  width: 100%;
  margin-bottom:24px;
}

.progress-value {
  border-radius: 100px;
  background: #0d6efd;
  height: 100%;
  width: 0;
  /* 核心:自动从当前宽度平滑过渡到新宽度,无需写死动画帧 */
  transition: width 1s ease;
}

HTML部分

删除label上冗余的内联onclick事件,给每个单选按钮加data-progress属性标记对应进度值,顺便把过老的jQuery1.4.4换成稳定的3.x版本:

<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>

<body>
<div class="wrapp">
  Speed
  <div class="progress">
    <div class="progress-value"></div>
  </div>
</div>

<div class="row">
<label>Group 1</label>
  <div class="col-6">
    <input type="radio" style="display:none;" id="js1" data-price="146.99" data-progress="25" value="option1a" name="ONE">
    <label for="js1">
      Option 1a
    </label>
  </div>
  <div class="col-6">
    <input type="radio" style="display:none;" id="js2" data-price="123.99" data-progress="50" value="option2a" name="ONE">
    <label for="js2">
      Option 2a
    </label>
  </div>
  
  <hr style="margin-top:24px;">
  
  <label>Group 2</label>
  
  <div class="col-6">
    <input type="radio" style="display:none;" id="js3" data-price="116.99" data-progress="25" value="option1b" name="TWO">
    <label for="js3">
      Option 1b
    </label>
  </div>
  <div class="col-6">
    <input type="radio" style="display:none;" id="js4" data-price="93.99" data-progress="40" value="option2b" name="TWO">
    <label for="js4">
      Option 2b
    </label>
  </div>
</div>
</body>

JS部分

删除所有冗余的全局点击监听、分散的事件绑定函数,统一在DOM加载完成后绑定一次事件:

$(document).ready(function() {
  // 给所有单选按钮绑定change事件,只绑一次
  $('input[type=radio]').on('change', function() {
    let total = 0;
    // 遍历所有已选中的单选,累加进度
    $('input[type=radio]:checked').each(function() {
      total += Number($(this).data('progress'));
    })
    // 进度上限锁100%,防止溢出
    total = Math.min(total, 100);
    // 更新进度条宽度,transition自动处理动画
    $('.progress-value').width(total + '%');
  })

  // 初始化默认选中首选项,加载页面就显示初始进度
  $('#js1').prop('checked', true).trigger('change');
})

扩展说明

  • 后续如果要加新的单选组,只需要给对应input加data-progress属性设置权重即可,不需要修改JS和CSS代码
  • 动画时长、缓动效果直接改.progress-value的transition属性就行,全局生效
  • 进度值可以根据业务需求自由调整,比如要让某个选项占更高权重,直接改data-progress的数字即可,不需要写新的动画关键帧

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 08:15:45