html表单无法直接显示上传进度,需用xmlhttprequest手动上传并监听xhr.upload.onprogress事件;formdata字段名须与后端一致,不可手动设置content-type;多文件需独立请求,ui更新应节流防卡顿。

HTML表单标签本身不处理上传进度——<form></form> 提交是同步整页跳转行为,没有进度事件。要显示进度条,必须绕开原生提交,用 JavaScript 手动控制上传过程,并监听底层网络事件。
核心机制:必须用 xhr.upload.onprogress
这是唯一稳定可行的方式:
- 监听对象只能是
xhr.upload,写成xhr.onprogress监听的是下载,上传时完全不触发 - 绑定时机必须在
xhr.open()之后、xhr.send()之前 - 每次触发的事件对象
e中,e.lengthComputable必须为true才能算百分比;若为false,说明后端没返回Content-Length,常见于 Nginx 代理截断或服务端配置问题 - 不要依赖
fetch:它原生不支持上传进度监听,强行分块上传会破坏multipart/form-data结构
FormData 构造不能出错
进度条动了,不代表后端真收到了文件:
- 文件字段名(
append('file', file)中的'file')必须和服务端约定完全一致 - 别手动设置
Content-Type请求头——XMLHttpRequest 会自动生成带正确boundary的multipart/form-data,设了反而导致解析失败 - 用
append()还是set()要看后端:重复字段名时,append()保留多个值,set()只留最后一个;Express + Multer 默认只取第一个 - 同时传 JSON 和文件,别把整个 JSON 字符串
append('data', JSON.stringify(obj)),应拆成独立字段,或让后端支持嵌套 multipart
进度条 UI 更新要注意细节
别只顾逻辑,UI 层容易翻车:
- 用
<progress></progress>标签语义清晰,但必须动态改value属性,不是改style.width - 需要动画、文字居中或状态提示(如“正在上传…”“上传完成”),推荐用
<div class="progress-bar"><div class="progress"></div></div>+ CSS transition - onprogress 可能每毫秒触发多次,直接更新 DOM 会造成卡顿,建议用
requestAnimationFrame或简单节流(例如 100ms 内最多更新一次) - Safari 对小文件的
upload.onprogress触发极不规律,可能只触发一次,这是它的实现策略,不是 bug
多文件上传要单独发起请求
一个 XMLHttpRequest 实例只能对应一个上传流程:
-
input[type="file"][multiple]选了多个文件,不能塞进同一个FormData一起发——那样e.loaded是累计值,无法区分每个文件进度 - 必须遍历
files列表,为每个File创建独立的XMLHttpRequest实例 - 用
let声明循环变量,或用闭包保存当前文件名,避免所有回调都引用到同一个file变量
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











