表单提交进度条不更新的主因是XMLHttpRequest事件绑定错误:必须在xhr.open()后、send()前绑定xhr.upload.onprogress而非xhr.onprogress;同时需同步更新aria-valuenow属性和style.width以驱动Bootstrap进度条视觉与可访问性。
表单提交时进度条不更新,XMLHttpRequest 事件没绑对
浏览器原生 xmlhttprequest 的 upload 对象才触发上传进度,不是 xhr 本身。很多人绑了 xhr.onprogress,但实际得写 xhr.upload.onprogress。
常见错误现象:ProgressEvent 根本不触发,或者只在完成时跳到 100%。
- 必须在
xhr.open()之后、xhr.send()之前绑定xhr.upload.onprogress -
event.loaded和event.total都要检查是否为 0,避免除零或 NaN - 如果用
fetch,它不支持上传进度——别硬套,老实用XMLHttpRequest
Bootstrap 进度条样式卡在 0%,aria-valuenow 没同步更新
Bootstrap 的进度条靠 aria-valuenow 属性和内联 style="width: XX%" 驱动视觉变化。只改属性不改 style,UI 不会动;只改 style 不更新属性,可访问性失效。
使用场景:文件上传、大表单 JSON 提交、带 FormData 的 multipart 请求。
- 每次拿到新进度值,必须同时设置:
el.setAttribute('aria-valuenow', percent)和el.style.width = percent + '%' - Bootstrap 5 要求进度条容器有
class="progress",子元素是class="progress-bar",缺一不可 - 别用
$(...).css(...)或classList.replace动态换 class 控制宽度——它不响应 width 变化
后端返回 200 但前端卡在 99%,Content-Length 缺失导致 event.total === 0
进度计算依赖 event.total,而它来自响应头的 Content-Length(下载)或请求体大小(上传)。上传进度中,event.total 是你传给 send() 的数据总字节数,但浏览器不一定能准确获取——尤其当用 FormData 且含文件时。
性能影响:手动计算 FormData 大小虽可行,但读取 Blob/File 会触发异步操作,反而拖慢上传启动。
- 优先信任
event.total;若为 0,先设进度条为 indeterminate(移除aria-valuenow,加class="progress-bar progress-bar-striped progress-bar-animated") - 不要在
onload里再设 100%——onprogress最后一次通常已是 100%,重复设置可能造成 UI 跳变 - Node.js 后端用
express时,确保没禁用req.headers['content-length'];Nginx 默认透传,但加了proxy_buffering off可能干扰
移动端点击提交无反应,preventDefault() 忘了或位置错了
表单默认提交会刷新页面,进度条刚动一下就没了。必须拦截,但容易漏掉或拦截过早。
容易踩的坑:用 button type="submit" 却只给按钮绑 click,没阻止 form 的 submit 事件;或者用了 return false 但函数是箭头函数,this 上下文错乱。
- 事件监听必须挂在
form元素上,用form.addEventListener('submit', e => { e.preventDefault(); ... }) - 别在按钮 click 里调
e.preventDefault()——它阻止不了表单提交行为 - Bootstrap 5 的
disabled状态要手动控制:submitButton.disabled = true,否则用户可能连点多次
真正麻烦的不是画出进度条,而是上传过程中网络中断、后端超时、用户切走页面这些边界情况——onerror、ontimeout、onabort 都得单独处理,且不能只靠 UI 提示,得留好重试入口和原始数据快照。











