最轻量方案是用原生progress元素+JS手动控制状态;它语义化、支持ARIA和键盘交互,需设max和value属性,IE10+原生支持;步骤条本质是状态机可视化,应按“选择文件→校验→构建FormData→发送→响应→解析”拆解节点,配合data-state切换样式;真实进度须通过XHR.upload.onprogress或axios的onUploadProgress获取,禁用setTimeout模拟。

直接用 progress 元素 + 手动控制状态是最轻量、兼容性最好、也最容易调试的方案。别一上来就套 UI 组件库或重写整个上传流程,90% 的步骤条需求靠原生 HTML + 少量 JS 就能闭环。
用 progress 元素做视觉主干
它不是装饰,是语义化进度容器,浏览器原生支持 aria 属性和键盘交互。不要用 div 模拟进度条再加一堆 role 和 tabindex。
-
progress必须设max(比如 100)和value(初始可为 0),否则不会渲染为进度态 - 不能通过 CSS 改变
value,必须用 JS 赋值:document.getElementById('uploadProgress').value = 35 - IE10+ 支持,无需 polyfill;如需旧 IE 兼容,降级为
span+ 宽度计算更稳妥
把上传流程拆成明确的 state 节点
“步骤条”本质是状态机可视化,不是时间轴。用户关心的是「当前卡在哪一步」,不是「过了几秒」。
- 典型节点:选择文件 → 校验格式/大小 → 构建
FormData→ 发送请求 → 等待响应 → 解析结果 - 每个节点对应一个
data-state值,例如data-state="selected"、data-state="uploading",用 class 切换高亮样式 - 避免把「上传中」和「上传完成」混在一个节点里——进度条走到 100% 不代表服务端已落盘,要等
response.status === 200后才进下一步
监听 XMLHttpRequest.upload.onprogress 或 onUploadProgress(axios)
这是唯一能拿到真实字节级进度的途径。表单 submit 后的 loading 动画不算进度条。
立即学习“前端免费学习笔记(深入)”;
- 原生 XHR:必须在
send()前绑定upload.onprogress,且event.lengthComputable为 true 才可信 - axios:传
onUploadProgress回调,注意它只在浏览器环境有效,Node.js 或某些打包配置下可能不触发 - 别用
setTimeout模拟进度——用户会发现「99% 卡住 10 秒」,体验比没进度条还差 - 小文件(
错误状态必须有独立步骤节点
上传失败不是进度中断,而是流程分支。步骤条上得标出「校验失败」「网络超时」「服务端拒绝」等具体原因。
- 不要只显示「上传失败,请重试」,要在步骤条下方插入
small提示,例如:<small>文件大于 50MB,请压缩后重试</small> - 如果支持断点续传或分片,失败节点应带「继续上传」按钮,而不是回到第一步重新选文件
- 网络错误(如
TypeError: Failed to fetch)和业务错误(如{ code: 4001, msg: "文件类型不支持" })要区分处理,前者可自动重试,后者必须人工干预
最常被忽略的一点:步骤条的「完成态」必须和服务端最终确认强绑定。前端收到 200 并不等于文件已可用——比如 OSS 上传需要回调通知,或后端异步转码未结束。这时候进度条停在 100%,但实际状态仍是「处理中」,得用轮询或 WebSocket 补充第二层状态同步。



















