每个文件需配独立lay-filter,避免进度覆盖;progress仅表示发送完成,done才代表服务器确认;预览应在choose回调中用FileReader实现;前端校验不可靠,必须后端严格限制。
每个文件必须配独立 lay-filter
用同一个 lay-filter="demo" 控制所有文件进度,后一个文件的进度会覆盖前一个,最终只看到最后一个文件的进度跳变。这不是 bug,是 element.progress() 的设计逻辑——它靠 lay-filter 匹配 dom 节点。
正确做法:给每个文件生成唯一标识,比如 "progress-" + index:
- HTML 中动态插入带不同
lay-filter的进度条,例如:<div class="layui-progress" lay-filter="progress-0"><div class="layui-progress-bar" lay-percent="0%"></div></div> - 在
progress回调里调用element.progress("progress-" + index, n + "%") - 别忘了在
done或error后把对应进度条设为"100%",否则可能卡在 99%
progress 到 100% 不代表上传完成
progress 回调里的 n === 100 只表示浏览器已把文件发完,但服务器还没处理完、没返回响应。这时候如果立刻弹“上传成功”,用户一刷新页面发现文件没存上,体验极差。
常见错误:在 progress 里判断 n === 100 就隐藏 loading 或启用按钮。
正确节奏:progress 只管“发了多少”,done 才是“服务器认了”,error 是“服务器拒了”。
- 大文件场景下,
progress到 100% 后可能还要等几秒才进done - 建议加个中间态提示,比如“正在保存…”
- 避免在
progress里直接操作 UI 状态(如禁用按钮、清空输入框)
预览和进度要分两套逻辑走
Layui upload 模块不处理文件读取和预览,所谓“多文件预览”,本质是选中文件 → 用 FileReader 逐个读取 → 把 dataURL 赋给 <img> 标签。这和上传进度完全无关,不能混在同一个回调里。
- 必须在
choose回调里遍历obj.files,不能等done—— 那时文件早发到服务器了 -
obj.files是FileList,不是数组,要用Array.from(obj.files)或手动循环 - 每个
File对象有name、size、type,可用来过滤非图片(比如跳过.pdf) - 别在
choose里直接调obj.upload(),否则会立刻上传,失去预览时机
前端校验 size 和 exts 是摆设
size: 10240(10MB)或 exts: "jpg|png" 是纯前端校验,用户在控制台几行代码就能绕过。进度条跑得再顺,传上来一个 500MB 的视频或 .php 文件,照样崩服务端。
真正可靠的限制必须落在后端:
- 检查文件大小(不只是
Content-Length,还要流式读取验证) - 校验 MIME 类型(不能只信
file.type) - 读取文件头魔数(比如 PNG 必须以
89 50 4E 47开头) -
accept: "images"会过滤掉 PDF、TXT,哪怕你写了exts,这个限制也只在 input 层面生效,不防篡改
进度条本身不难,难的是把「发出去」「收回来」「出错了」三个状态和 UI 状态严格对齐。稍一松懈,就会出现进度条卡住、按钮状态错乱、用户以为传完了其实没落库这些情况。


















