在现代网页设计中,进度步骤(Progress Steps) 是一种常见的 UI 模式,常用于引导用户完成注册流程、多步表单、教程或任何需要分步骤操作的场景。本文将带你从零开始构建一个美观且功能完整的 “进度步骤”组件,并详细讲解每一部分代码的作用和实现原理。
🧩 项目结构概览
我们使用以下三种技术来构建这个组件:
- HTML:定义页面结构
- CSS:控制样式与动画效果
- JavaScript:处理用户交互逻辑
最终效果是一个带有动态进度条、可点击切换步骤、按钮状态自动更新的交互式组件。
📄 HTML 结构
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<!-- 确保页面在移动设备上正确缩放 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- 引入自定义样式表 -->
<link rel="stylesheet" href="style.css" />
<!-- 页面标题 -->
<title>Progress Steps</title>
</head>
<body>
<!-- 主容器:包含整个进度组件 -->
<div class="container">
<!-- 进度条区域 -->
<div class="progress-container">
<!-- 实际进度条,宽度由 JS 控制 -->
<div class="progress" id="progress"></div>
<!-- 步骤点:每个 circle 表示一个步骤 -->
<div class="circle active">1</div>
<div class="circle">2</div>
<div class="circle">3</div>
<div class="circle">4</div>
</div>
<!-- 操作按钮 -->
<button class="btn" id="prev" disabled>Prev</button>
<button class="btn" id="next">Next</button>
</div>
<!-- 引入脚本文件 -->
<script src="script.js"></script>
</body>
</html>
🔍 HTML 解释:
.progress-container
包含了所有步骤点和进度条。.circle
表示每一个步骤,.active
类表示当前激活的步骤。#progress
是动态变化的进度条。- 两个按钮分别控制“上一步”和“下一步”,初始时“上一步”被禁用。
🎨 CSS 样式
/* 引入 Google Fonts 中的 Muli 字体 */
@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');
/* 定义全局变量,用于控制进度条和圆圈的颜色 */
:root {
--line-border-fill: #3498db; /* 已完成进度的颜色 */
--line-border-empty: #383838; /* 未完成进度的颜色 */
}
/* 设置所有元素的 box-sizing 属性为 border-box,确保 padding 和 border 不会影响元素宽度 */
* {
box-sizing: border-box;
}
/* 页面主体样式设置 */
body {
background-color: #f1f1f1; /* 背景颜色 */
font-family: 'Muli', sans-serif; /* 使用引入的 Muli 字体 */
display: flex; /* 使用 Flex 布局 */
align-items: center; /* 子元素垂直居中 */
justify-content: center; /* 子元素水平居中 */
height: 100vh; /* 占满整个视口高度 */
overflow: hidden; /* 隐藏溢出内容 */
margin: 0; /* 移除默认的 body 外边距 */
}
/* 主容器样式 */
.container {
text-align: center; /* 文本和内联元素居中 */
}
/* 进度条容器样式 */
.progress-container {
display: flex; /* 使用 Flex 布局排列子元素 */
justify-content: space-between; /* 子元素之间均匀分布 */
position: relative; /* 相对定位,用于绝对定位伪元素和进度条 */
margin-bottom: 30px; /* 底部外边距 */
max-width: 100%; /* 最大宽度为父元素的宽度 */
width: 350px; /* 固定宽度 */
}
/* 绘制灰色背景线 */
.progress-container::before {
content: ''; /* 必须定义 content 属性 */
background-color: var(--line-border-empty); /* 使用定义的未完成颜色 */
position: absolute; /* 绝对定位 */
top: 50%; /* 顶部中心位置 */
left: 0; /* 左边起始位置 */
transform: translateY(-50%); /* 上下居中 */
height: 4px; /* 线的高度 */
width: 100%; /* 线的长度 */
z-index: -1; /* 放在底层 */
}
/* 当前已完成进度条 */
.progress {
background-color: var(--line-border-fill); /* 使用定义的已完成颜色 */
position: absolute; /* 绝对定位 */
top: 50%; /* 顶部中心位置 */
left: 0; /* 左边起始位置 */
transform: translateY(-50%); /* 上下居中 */
height: 4px; /* 进度条的高度 */
width: 0%; /* 初始宽度为0%,通过 JavaScript 动态改变 */
z-index: -1; /* 放在底层 */
transition: 0.4s ease; /* 平滑过渡效果 */
}
/* 步骤圆圈样式 */
.circle {
background-color: #f1f1f1; /* 默认背景色 */
color: #e2e2e2; /* 默认文本颜色 */
border-radius: 50%; /* 圆形 */
height: 30px; /* 高度 */
width: 30px; /* 宽度 */
display: flex; /* 使用 Flex 布局 */
align-items: center; /* 子元素垂直居中 */
justify-content: center; /* 子元素水平居中 */
border: 3px solid var(--line-border-empty); /* 边框样式 */
transition: 0.4s ease; /* 平滑过渡效果 */
}
/* 激活状态下的步骤圆圈样式 */
.circle.active {
border-color: var(--line-border-fill); /* 改变边框颜色为已完成颜色 */
}
/* 按钮样式 */
.btn {
background-color: var(--line-border-fill); /* 背景颜色 */
color: #fff; /* 文字颜色 */
border: 0; /* 移除默认边框 */
border-radius: 6px; /* 圆角半径 */
cursor: pointer; /* 鼠标指针变为手型 */
font-family: inherit; /* 继承父级字体 */
padding: 8px 30px; /* 内边距 */
margin: 5px; /* 外边距 */
font-size: 14px; /* 字体大小 */
}
/* 按钮按下时的效果 */
.btn:active {
transform: scale(0.98); /* 缩放效果 */
}
/* 移除按钮聚焦时的默认轮廓 */
.btn:focus {
outline: 0;
}
/* 按钮禁用状态 */
.btn:disabled {
background-color: var(--line-border-empty); /* 更改背景颜色 */
cursor: not-allowed; /* 鼠标指针样式 */
}
✨ 样式亮点:
- 使用 CSS 变量
--line-border-fill
和--line-border-empty
实现主题色统一管理。 - 使用伪元素
::before
绘制背景线,代表未完成步骤。 - 进度条通过
transform
或width
动态变化,视觉过渡平滑。 - 按钮添加了点击反馈和禁用状态样式,提升用户体验。
⚙️ JavaScript 交互逻辑
// 获取页面上的进度条、上一步和下一步按钮以及所有的步骤圆圈元素
const progress = document.getElementById('progress'); // 进度条元素
const prev = document.getElementById('prev'); // 上一步按钮
const next = document.getElementById('next'); // 下一步按钮
const circles = document.querySelectorAll('.circle'); // 步骤圆圈元素集合
let currentActive = 1; // 当前激活的步骤,默认为第一个步骤
// 给下一步按钮添加点击事件监听器
next.addEventListener('click', () => {
currentActive++; // 增加当前激活的步骤索引
if(currentActive > circles.length) { // 如果超出最大步骤数,则设置为最大值
currentActive = circles.length;
}
update(); // 更新界面显示
});
// 给上一步按钮添加点击事件监听器
prev.addEventListener('click', () => {
currentActive--; // 减少当前激活的步骤索引
if(currentActive < 1) { // 如果小于最小步骤数,则设置为最小值
currentActive = 1;
}
update(); // 更新界面显示
});
/**
* 更新界面函数,根据当前激活的步骤更新各个UI组件的状态
*/
function update() {
// 遍历所有步骤圆圈,根据当前激活的步骤更新它们的样式
circles.forEach((circle, idx) => {
if(idx < currentActive) {
circle.classList.add('active'); // 激活状态
} else {
circle.classList.remove('active'); // 非激活状态
}
});
const actives = document.querySelectorAll('.active'); // 获取所有激活状态的步骤圆圈
// 根据激活状态的步骤圆圈数量计算进度条宽度百分比
progress.style.width = ((actives.length - 1) / (circles.length - 1)) * 100 + '%';
// 控制上一步和下一步按钮是否可用
if(currentActive === 1) {
prev.disabled = true; // 第一步时禁用上一步按钮
} else if(currentActive === circles.length) {
next.disabled = true; // 最后一步时禁用下一步按钮
} else {
prev.disabled = false; // 启用上一步按钮
next.disabled = false; // 启用下一步按钮
}
}
💡 JavaScript 解析:
currentActive
控制当前处于哪个步骤。- 点击“下一步”或“上一步”后,修改该值并调用
update()
函数刷新界面。 update()
函数负责:- 更新每个步骤点的
active
类状态; - 动态设置进度条宽度;
- 控制“上一步”和“下一步”按钮的启用/禁用状态。
- 更新每个步骤点的
🧪 效果演示
运行以上代码后,你会看到一个漂亮的进度步骤组件,支持:
- 点击“下一步”逐步推进;
- 点击“上一步”回退到前面的步骤;
- 进度条随着步骤变化动态扩展;
- 当前步骤高亮显示;
- 到达第一步或最后一步时对应按钮自动禁用。
📦 扩展建议
你可以进一步优化这个组件,例如:
- 将其封装成 Vue / React 组件;
- 添加动画效果(如淡入淡出);
- 支持键盘方向键导航;
- 配合本地存储保存当前步骤状态;
- 增加步骤内容区域,展示更多信息。
📝 总结
通过本文,你已经掌握了一个完整的 “进度步骤”组件 的开发流程。这个组件不仅外观美观,而且功能完整,适用于各种需要分步骤引导用户的场景。希望你能将它应用到自己的项目中,并在此基础上进行更多个性化扩展!
如果你喜欢这篇文章,欢迎分享给你的朋友或同事,也欢迎继续关注我的博客获取更多前端实战技巧!