上传前须立即视觉反馈,禁用按钮并设aria-busy;onprogress必须绑定xhr.upload且在open后send前设置;多文件需聚合状态、动态更新文案,失败不中断队列。

点击上传按钮后立刻显示“正在上传”提示
用户点下上传按钮到服务器响应之间存在明显延迟,必须在 send() 调用前就给出视觉反馈,否则容易重复点击。关键不是等后端返回,而是「发起请求即提示」。
- 禁用按钮或添加 loading 状态类(如
btn-loading),同时设置button.disabled = true或button.setAttribute('aria-busy', 'true') - 在 DOM 中插入一个临时提示元素(如
<div id="upload-status">⏳ 正在上传…</div>),或复用已有状态栏 - 不要等到
xhr.onload才操作 UI——那已经是上传完成之后了 - 如果使用
fetch,需在fetch(...)调用前立即更新 UI;若用XMLHttpRequest,则在xhr.send()前执行
上传进度条动不起来?先检查 onprogress 绑在哪
90% 的“进度条不动”问题,是因为把 onprogress 监听器绑错了对象:它必须挂在 xhr.upload 上,而不是 xhr 本身。绑在 xhr 上监听的是下载进度,对上传毫无意义。
- 正确写法:
xhr.upload.onprogress = function(e) { ... } - 必须在
xhr.open()之后、xhr.send()之前设置,顺序错就失效 - 如果
e.lengthComputable === false,说明服务端没返回Content-Length(常见于 Nginx 代理截断、无 CORS 暴露头),此时只能显示“上传中…”而无法算百分比 - 用
curl -I http://your-api/upload检查响应头是否含Access-Control-Expose-Headers: Content-Length
上传失败时别只弹 alert,要同步按钮状态和文案
服务端返回 4xx(如 400、413、415)或网络异常时,UI 必须立刻反映“被拒”,但不能简单禁用按钮——用户需要重试入口。
- 移除可能存在的成功态类(如
btn-success),添加警告类(如btn-warning) - 更新提示文案为具体原因:
"文件过大(限5MB)"或"类型不支持,请上传 JPG/PNG" - 设置
button.title提供悬停提示,辅助屏幕阅读器 - 避免在
input[type="file"].change事件里提前加警告——此时文件还没提交,校验尚未发生 - 网络超时或中断也应归入警告态,统一文案为
"上传失败,请重试"
多文件上传时提示容易混乱,得靠状态聚合
一次传 10 个文件,每个都有自己的进度和可能的失败项,直接堆叠提示会淹没用户。真实场景下应聚合状态,而非逐个反馈。
- 用一个总进度条显示整体完成度:
Math.round((totalLoaded / totalSize) * 100) - 失败文件单独记录,上传结束后统一展示错误列表(如
<ul class="error-list"></ul>) - 按钮文案动态切换:
"上传中(3/10)"→"上传完成(2失败)"→"重新上传失败项" - 别让单个文件失败中断整个队列——除非业务强要求原子性,否则应继续上传其余文件
真正难的不是写几行 onprogress,而是让提示节奏和服务端实际行为严丝合缝:进度条卡住,往往因为后端悄悄吞掉了 Content-Length;按钮没恢复,常常是 catch 分支里忘了 removeAttribute('aria-busy')。这些细节不处理,用户第一反应永远是“页面卡了”。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











