一、前言:为什么进度条动画是 JS 入门必练案例?
进度条是前端开发中高频出现的交互组件,文件上传、页面加载、表单提交、视频播放等场景都离不开它,也是前端面试中基础的实操考点。
这个实战案例能一次性打通DOM 元素操作、JS 定时器运用、CSS 过渡 / 动画、数值动态计算、事件绑定5 个 JS 入门核心知识点,从基础的固定进度加载,到可控制的手动进度、自动加载完成回调,层层递进的实现方式,让新手既能掌握核心原理,又能适配实际开发的不同需求。
本文将从 0 到 1 实现 3 种常用的进度条动画:基础自动加载进度条、点击控制增减的交互式进度条、带进度百分比的精准进度条,同时补充4 个实战扩展方向和新手高频踩坑点,实现的进度条支持自定义颜色、高度、加载速度,可直接复用在实际项目中。

二、需求分析(明确目标,避免盲目编码)
核心需求(必实现)
✅ 实现基础进度条结构:外层容器 + 内层进度条,样式美观且可自定义;
✅ 原生 JS 实现进度条平滑加载动画,支持设置加载总时长;
✅ 实现进度条数值动态计算,精准匹配进度条宽度变化;
✅ 进度条加载完成后触发回调,支持后续业务逻辑执行;
✅ 样式适配不同场景,支持自定义主色、高度、圆角。
扩展需求(进阶优化)
✅ 添加进度百分比实时显示,视觉更直观;
✅ 实现手动控制进度:点击按钮实现进度增加 / 减少 / 重置;
✅ 支持进度条暂停 / 继续功能,适配上传 / 加载暂停场景;
✅ 实现多色渐变进度条,提升视觉体验,适配个性化需求。
三、实现步骤(原理 + 代码,步步拆解)
3.1 搭建 HTML 结构:语义化 + 可扩展
核心包含进度条外层容器、内层进度条、进度百分比显示三部分,通过class控制样式,id标识核心元素方便 JS 操作,结构简洁且可扩展,符合 “结构与样式分离” 原则:
html
预览
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原生JS实现进度条动画 | 前端实战</title>
<!– CSS/JS后续引入 –>
</head>
<body>
<div class="progress-container">
<h3>原生JS进度条动画</h3>
<!– 进度条核心容器 –>
<div class="progress-wrap">
<!– 内层进度条(动态变化) –>
<div id="progressBar" class="progress-bar"></div>
<!– 进度百分比显示 –>
<span id="progressText" class="progress-text">0%</span>
</div>
<!– 进度控制按钮组 –>
<div class="progress-btn-group">
<button id="addBtn" class="progress-btn">+5%</button>
<button id="reduceBtn" class="progress-btn">-5%</button>
<button id="resetBtn" class="progress-btn">重置</button>
<button id="pauseBtn" class="progress-btn">暂停/继续</button>
</div>
</div>
</body>
</html>
关键说明:
3.2 编写 CSS 样式:美观 + 动画 + 可自定义
重点实现进度条的基础样式、平滑过渡动画、百分比文字居中显示,同时美化控制按钮,支持自定义进度条主色、高度、圆角,核心通过transition实现进度条宽度变化的平滑动画,避免生硬切换:
css
/* 全局样式重置:消除浏览器默认差异 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
}
body {
min-height: 100vh;
padding: 80px 50px;
background-color: #f5f7fa;
}
/* 进度条外层容器 */
.progress-container {
max-width: 600px;
margin: 0 auto;
}
.progress-container h3 {
color: #333;
font-size: 20px;
margin-bottom: 20px;
font-weight: 600;
}
/* 进度条背景容器 */
.progress-wrap {
width: 100%;
height: 20px;
background-color: #e5e6eb;
border-radius: 10px;
position: relative;
margin-bottom: 20px;
overflow: hidden; /* 隐藏内层进度条超出部分 */
}
/* 核心进度条 */
.progress-bar {
height: 100%;
width: 0; /* 初始宽度为0,JS动态修改 */
background-color: #409eff; /* 主色,可自定义 */
border-radius: 10px;
/* 平滑过渡动画:宽度变化0.3s缓动 */
transition: width 0.3s ease;
}
/* 进度百分比文字 */
.progress-text {
position: absolute;
top: 50%;
right: 10px;
transform: translateY(-50%);
font-size: 14px;
color: #666;
font-weight: 500;
}
/* 控制按钮组 */
.progress-btn-group {
display: flex;
gap: 12px;
flex-wrap: wrap;
}
/* 按钮样式 */
.progress-btn {
padding: 8px 16px;
font-size: 14px;
color: #fff;
background-color: #409eff;
border: none;
border-radius: 6px;
cursor: pointer;
transition: all 0.2s ease;
}
/* 按钮交互反馈 */
.progress-btn:hover {
background-color: #66b1ff;
}
.progress-btn:active {
background-color: #337ecc;
transform: scale(0.98);
}
核心优化点:
3.3 编写 JS 核心逻辑(基础 + 进阶,层层递进)
核心实现自动加载进度条、手动控制进度、进度暂停 / 继续、加载完成回调四大功能,逻辑清晰且易扩展,通过定时器实现进度的动态增加,通过数值判断保证进度在 0-100% 之间,避免超出边界。
3.3.1 定义核心变量
先定义全局核心变量,包括进度条元素、当前进度、定时器、加载状态,方便后续函数调用和修改:
javascript
运行
// 1. 获取所有核心DOM元素
const progressBar = document.getElementById('progressBar');
const progressText = document.getElementById('progressText');
const addBtn = document.getElementById('addBtn');
const reduceBtn = document.getElementById('reduceBtn');
const resetBtn = document.getElementById('resetBtn');
const pauseBtn = document.getElementById('pauseBtn');
// 2. 定义核心全局变量
let currentProgress = 0; // 当前进度,初始为0
let progressTimer = null; // 进度条定时器,用于自动加载
let isLoading = true; // 加载状态:true-加载中,false-暂停
const speed = 50; // 加载速度:数值越小越快,单位ms
const step = 1; // 每次加载的步长:数值越大,进度增加越快
3.3.2 封装进度更新函数(核心复用函数)
将进度条宽度修改和百分比文字更新抽离为独立函数,避免代码冗余,后续所有进度变化都调用此函数,保证逻辑统一:
javascript
运行
// 封装进度更新函数:统一修改进度条和文字
function updateProgress(progress) {
// 限制进度在0-100%之间,避免超出边界
if (progress < 0) progress = 0;
if (progress > 100) progress = 100;
// 更新当前进度
currentProgress = progress;
// 修改进度条宽度
progressBar.style.width = `${currentProgress}%`;
// 更新百分比文字
progressText.innerText = `${currentProgress}%`;
// 进度加载完成的回调逻辑
if (currentProgress === 100) {
clearInterval(progressTimer); // 清除定时器
isLoading = false; // 修改加载状态
alert('进度条加载完成!'); // 可替换为实际业务逻辑,如上传完成、页面加载完毕
}
}
3.3.3 实现自动加载进度条功能
通过setInterval定时器实现进度条的自动加载,每次定时器执行,进度增加指定步长,调用updateProgress函数更新视图,是进度条动画的核心 JS 逻辑:
javascript
运行
// 实现自动加载进度条
function autoProgress() {
// 先清除原有定时器,避免多次点击创建多个定时器
clearInterval(progressTimer);
// 判断如果是暂停状态,直接返回(仅加载中时执行)
if (!isLoading) return;
// 创建定时器,动态增加进度
progressTimer = setInterval(() => {
updateProgress(currentProgress + step);
}, speed);
}
// 页面加载完成后,启动自动进度条
window.onload = function() {
autoProgress();
};
3.3.4 实现手动控制进度功能
给增减、重置按钮绑定点击事件,实现点击 + 5%、点击 – 5%、** 一键重置为 0%** 的功能,核心是修改currentProgress并调用updateProgress函数:
javascript
运行
// 点击+5%按钮
addBtn.addEventListener('click', () => {
updateProgress(currentProgress + 5);
});
// 点击-5%按钮
reduceBtn.addEventListener('click', () => {
updateProgress(currentProgress – 5);
});
// 点击重置按钮
resetBtn.addEventListener('click', () => {
clearInterval(progressTimer); // 清除定时器
currentProgress = 0; // 重置当前进度
isLoading = true; // 恢复加载状态
updateProgress(0); // 更新视图
autoProgress(); // 重新启动自动加载
});
3.3.5 实现进度条暂停 / 继续功能
通过修改isLoading加载状态,实现进度条的暂停和继续,点击按钮时切换状态,同时重新执行自动加载函数:
javascript
运行
// 点击暂停/继续按钮
pauseBtn.addEventListener('click', () => {
isLoading = !isLoading; // 切换加载状态
if (isLoading && currentProgress < 100) {
autoProgress(); // 继续加载
} else {
clearInterval(progressTimer); // 暂停加载,清除定时器
}
});
原理拆解:
四、完整源码(直接复制可用,含所有功能)
将 HTML、CSS、JS 整合在一个文件中,直接保存为index.html用浏览器打开即可运行,无需额外引入任何资源,支持自动加载、手动增减、重置、暂停 / 继续、百分比显示所有功能:
html
预览
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原生JS实现进度条动画 | 前端实战</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
}
body {
min-height: 100vh;
padding: 80px 50px;
background-color: #f5f7fa;
}
.progress-container {
max-width: 600px;
margin: 0 auto;
}
.progress-container h3 {
color: #333;
font-size: 20px;
margin-bottom: 20px;
font-weight: 600;
}
.progress-wrap {
width: 100%;
height: 20px;
background-color: #e5e6eb;
border-radius: 10px;
position: relative;
margin-bottom: 20px;
overflow: hidden;
}
.progress-bar {
height: 100%;
width: 0;
background-color: #409eff;
border-radius: 10px;
transition: width 0.3s ease;
}
.progress-text {
position: absolute;
top: 50%;
right: 10px;
transform: translateY(-50%);
font-size: 14px;
color: #666;
font-weight: 500;
}
.progress-btn-group {
display: flex;
gap: 12px;
flex-wrap: wrap;
}
.progress-btn {
padding: 8px 16px;
font-size: 14px;
color: #fff;
background-color: #409eff;
border: none;
border-radius: 6px;
cursor: pointer;
transition: all 0.2s ease;
}
.progress-btn:hover {
background-color: #66b1ff;
}
.progress-btn:active {
background-color: #337ecc;
transform: scale(0.98);
}
/* 移动端适配 */
@media (max-width: 400px) {
.progress-container {
padding: 0 20px;
}
.progress-btn {
padding: 6px 12px;
font-size: 12px;
}
}
</style>
</head>
<body>
<div class="progress-container">
<h3>原生JS进度条动画</h3>
<div class="progress-wrap">
<div id="progressBar" class="progress-bar"></div>
<span id="progressText" class="progress-text">0%</span>
</div>
<div class="progress-btn-group">
<button id="addBtn" class="progress-btn">+5%</button>
<button id="reduceBtn" class="progress-btn">-5%</button>
<button id="resetBtn" class="progress-btn">重置</button>
<button id="pauseBtn" class="progress-btn">暂停/继续</button>
</div>
</div>
<script>
// 获取核心DOM元素
const progressBar = document.getElementById('progressBar');
const progressText = document.getElementById('progressText');
const addBtn = document.getElementById('addBtn');
const reduceBtn = document.getElementById('reduceBtn');
const resetBtn = document.getElementById('resetBtn');
const pauseBtn = document.getElementById('pauseBtn');
// 核心全局变量
let currentProgress = 0;
let progressTimer = null;
let isLoading = true;
const speed = 50; // 加载速度,ms
const step = 1; // 每次加载步长
// 封装进度更新函数
function updateProgress(progress) {
if (progress < 0) progress = 0;
if (progress > 100) progress = 100;
currentProgress = progress;
progressBar.style.width = `${currentProgress}%`;
progressText.innerText = `${currentProgress}%`;
// 加载完成回调
if (currentProgress === 100) {
clearInterval(progressTimer);
isLoading = false;
alert('进度条加载完成!');
}
}
// 自动加载进度条
function autoProgress() {
clearInterval(progressTimer);
if (!isLoading) return;
progressTimer = setInterval(() => {
updateProgress(currentProgress + step);
}, speed);
}
// 页面加载启动自动进度条
window.onload = function() {
autoProgress();
};
// 绑定按钮事件
addBtn.addEventListener('click', () => updateProgress(currentProgress + 5));
reduceBtn.addEventListener('click', () => updateProgress(currentProgress – 5));
resetBtn.addEventListener('click', () => {
clearInterval(progressTimer);
currentProgress = 0;
isLoading = true;
updateProgress(0);
autoProgress();
});
pauseBtn.addEventListener('click', () => {
isLoading = !isLoading;
isLoading && currentProgress < 100 ? autoProgress() : clearInterval(progressTimer);
});
</script>
</body>
</html>
五、效果演示
将上述代码保存为index.html,用任意浏览器打开即可看到完整效果,所有功能均可正常使用:
六、新手高频踩坑点 & 解决方案(核心提分点)
新手实操实现进度条动画时,容易出现进度条不加载、加速加载、超出边界等问题,以下是6 个高频踩坑点及对应的解决方案,帮你避坑少走弯路:
表格
| 进度条无动画,生硬跳变 | 未给进度条添加transition过渡属性,或过渡属性绑定错误 | 给progress-bar添加transition: width 0.3s ease,保证宽度变化时有平滑动画 |
| 多次点击按钮,进度条 “加速” 加载 | 未清除原有定时器,多次创建setInterval导致多个定时器同时运行 | 每次创建新定时器前,先执行clearInterval(progressTimer),清除原有定时器 |
| 进度条进度超出 100% 或为负数 | 未对进度值做边界判断,手动增减时进度超出 0-100% | 在updateProgress函数内添加判断,限制progress在 0-100% 之间 |
| JS 报错:无法获取元素的 style 属性 | JS 代码写在<head>中,DOM 元素未加载完成就执行 JS | 将 JS 代码放在<body>最后,或通过window.onload包裹 JS 逻辑 |
| 进度百分比文字与进度条不同步 | 手动修改进度时,未调用统一的updateProgress函数 | 所有进度变化都通过updateProgress函数实现,保证视图和文字统一更新 |
| 进度条加载完成后,仍继续加载 | 未在完成时清除定时器,或未修改加载状态 | 进度为 100% 时,执行clearInterval(progressTimer)并将isLoading设为false |
七、扩展优化思路(带核心代码,落地性强)
基础版进度条实现后,可根据实际开发需求进行扩展,以下是4 个常用的优化方向,附核心实现代码,直接复制即可复用,适配不同业务场景:
扩展 1:实现多色渐变进度条(视觉升级)
修改 CSS 样式,通过linear-gradient实现渐变进度条,支持自定义渐变颜色,适配个性化的页面设计:
css
/* 替换原有progress-bar的background-color */
.progress-bar {
height: 100%;
width: 0;
/* 蓝到红渐变,可自定义渐变颜色和方向 */
background: linear-gradient(90deg, #409eff, #67c23a, #e6a23c, #f56c6c);
border-radius: 10px;
transition: width 0.3s ease;
}
扩展 2:实现圆形进度条(适配数据统计场景)
基于 Canvas 实现圆形进度条,搭配百分比文字,适用于数据统计、个人中心等场景,核心代码如下(替换原有 HTML 和 CSS 的进度条部分):
html
预览
<!– 圆形进度条HTML –>
<div class="circle-progress-wrap">
<canvas id="circleCanvas" width="150" height="150"></canvas>
<span id="circleText" class="circle-text">0%</span>
</div>
css
/* 圆形进度条CSS */
.circle-progress-wrap {
position: relative;
width: 150px;
height: 150px;
margin-bottom: 20px;
}
#circleCanvas {
width: 100%;
height: 100%;
}
.circle-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 18px;
color: #409eff;
font-weight: 600;
}
javascript
运行
// 圆形进度条JS逻辑
const canvas = document.getElementById('circleCanvas');
const ctx = canvas.getContext('2d');
const circleText = document.getElementById('circleText');
const r = canvas.width / 2 – 10; // 圆的半径
// 封装圆形进度更新函数
function updateCircleProgress(progress) {
if (progress < 0) progress = 0;
if (progress > 100) progress = 100;
// 清空画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 绘制背景圆
ctx.beginPath();
ctx.arc(r + 10, r + 10, r, 0, 2 * Math.PI);
ctx.strokeStyle = '#e5e6eb';
ctx.lineWidth = 10;
ctx.stroke();
// 绘制进度圆
ctx.beginPath();
ctx.arc(r + 10, r + 10, r, -Math.PI / 2, 2 * Math.PI * (progress / 100) – Math.PI / 2);
ctx.strokeStyle = '#409eff';
ctx.lineWidth = 10;
ctx.lineCap = 'round'; // 进度条两端圆角
ctx.stroke();
// 更新文字
circleText.innerText = `${progress}%`;
}
// 在原有updateProgress函数中调用
function updateProgress(progress) {
// 原有逻辑…
updateCircleProgress(progress); // 新增圆形进度更新
}
扩展 3:实现根据文件上传速度动态更新进度(实际业务适配)
结合XMLHttpRequest实现文件上传进度的实时同步,进度条根据实际上传百分比动态更新,适配文件上传场景:
javascript
运行
// 文件上传进度同步
const uploadInput = document.getElementById('uploadInput');
uploadInput.addEventListener('change', (e) => {
const file = e.target.files[0];
if (!file) return;
const formData = new FormData();
formData.append('file', file);
const xhr = new XMLHttpRequest();
xhr.open('POST', '/upload', true);
// 监听上传进度
xhr.upload.addEventListener('progress', (e) => {
if (e.lengthComputable) {
// 计算上传百分比
const percent = (e.loaded / e.total) * 100;
updateProgress(Math.floor(percent)); // 同步到进度条
}
});
xhr.send(formData);
});
扩展 4:实现进度条加载完成后自动跳转到新页面
将原有加载完成的弹窗提示,替换为页面跳转功能,适配 “页面加载完成后跳转到首页”“上传完成后跳转到结果页” 等业务场景:
javascript
运行
// 替换updateProgress函数内的完成回调
if (currentProgress === 100) {
clearInterval(progressTimer);
isLoading = false;
// 延迟1秒跳转到新页面,让用户看到加载完成的状态
setTimeout(() => {
window.location.href = 'https://www.baidu.com'; // 替换为目标链接
}, 1000);
}
八、核心知识点总结(凝练易记,新手必背)
本次实战案例覆盖了 JS 和 CSS 的多个核心知识点,都是前端入门必须掌握的内容,凝练总结如下,方便新手记忆和复习:
九、互动与拓展
✅ 新手建议:先实现基础的自动加载进度条,再逐步添加手动控制、暂停 / 继续功能,最后尝试扩展渐变进度条、圆形进度条,循序渐进加深理解;
✅ 思考题:如何实现一个带加载动画的进度条(如进度条内有流动的光点)?(提示:通过 CSS 动画 + 伪元素实现);
✅ 实战拓展:如何实现多进度条联动(如多个文件上传,每个文件对应一个进度条)?(提示:通过循环创建 DOM 元素和独立变量实现);
✅ 问题反馈:如果实操中遇到任何问题,或想实现其他扩展功能(如进度条拖拽、自定义加载步长),评论区留言,我会第一时间解答~
创作不易,点赞 + 收藏 + 关注,后续持续更新 JS 零基础必练实战案例,从入门到精通,一步步带你搞定前端交互开发!





