文件上传 · upload
上传是「导入 CSV / 附一份财报 / 传凭证」的必经入口。这个组件的核心不在拖放区好看, 而在于:JS 没加载时它仍然是能用的,以及文件有没有真的进到表单里。
1 · 基础形态:零 JS 也能用
支持 CSV / XLSX,单个不超过 20 MB
这一块没有任何 JS:浏览器原生的"选择文件"按钮经
::file-selector-button 美化,选完立刻在按钮右侧回显文件名 ——
不需要脚本读 files 再写进 DOM。表单提交、FormData、
accept 过滤全走原生路径。
2 · 增强形态:拖放区 + 文件列表
可以一次选多个;再次拖入会替换整个列表
拖放区是一个 <label for>:点它 = 原生打开选择器,
这一步不依赖 JS。脚本只负责三件事 —— 把拖入的 File 塞进
input.files、重画列表、派发 fl-upload。
所以 <form> 拿到的永远是真实文件,不是"组件自己记的一份清单"。
3 · 上传中:进度既是图形也是文字
- 待上传 2025年度审计报告.pdf
- 已完成 应付账款明细.xlsx
- 失败 往来余额扫描件.pdf
三个状态的差别不只是颜色:左侧图形(空心圆 / 勾 / 叹号)、 中间文件名的灰度、以及右侧那行文字("上传中 42%" / "2.4 MB" / "超过 20 MB")。 把这一块截图转成灰度打印,信息一条都不丢。
4 · 校验拒绝:一个都没收进来
下面这一组是脚本真实拖入 3 个不合规文件的结果
被拒的文件不会进入 input.files ——
它们根本没被接收,所以提交时不会悄悄带上一个 30 MB 的扫描件。
拒绝原因写在文件名的位置,不是只把边框变红。
5 · 紧凑档(侧栏 / 抽屉)
6 · 槽宽适配(看槽宽,不看视口)
左侧这块是 240px 宽的槽(外层加了 data-cq)。
它比右边窄,但没有"响应式跳跃":内边距与图标各降一档,限制说明没有被藏起来 ——
藏掉它,用户就不知道该选什么文件了。
7 · 禁用
先在"基础信息"里选好主体类型,这里才能上传
禁用不用 opacity:半透明会让文字对比度随底色漂移,
暗色下直接不达标。这里换的是明确色值,边框同时从虚线变实线 ——
不用颜色也能看出"这一档不一样"。
对比:两种"拖放区"
❌ 常见写法:拖放区是唯一入口
把原生 <input> 设成 display:none 图省事 —— 两栏看起来一模一样,差别在键盘:
后果是键盘 Tab 永远聚焦不到它(不可聚焦元素进不了 Tab 序列),
读屏也拿不到可访问名字 —— 鼠标用户能用,键盘用户完全无法上传。
✅ 本库:隐藏的是像素,不是控件
同样看不见原生控件,但它只是 1px + opacity:0:
仍在 Tab 序列里、仍在表单里、仍能被 label 触发。
聚焦时焦点环画在拖放区上,用户看到的是"这块被选中了"。