Upload 上传
点击或拖拽选择文件,展示文件列表与上传进度。支持真实上传通道(action XHR / custom-request 逃生舱)、上传前校验转换、失败重试与取消。
基础用法
基础(选择文件)
多选与数量限制
多选 + max
max 限制最多可选文件数,accept 过滤文件类型;超出 max 的文件被拒绝并派发 oas-exceed-limit。
自动上传
自动上传(模拟进度)
auto-upload 时添加文件即自动上传;未设置 action / custom-request 时为模拟进度(内置定时器推进,仅作展示兜底,不发起网络请求),进度条复用 oas-progress。
拖拽上传
拖拽上传
将文件直接拖入虚线区域,松开即添加(支持多选);拖入时区域高亮提示。disabled 时拖拽会显示禁止光标且不接收文件。
照片墙
list-type 控制列表样式:list(默认,文本行)、picture(列表带小缩略图)、picture-card(卡片缩略图墙)。
picture-card 卡片墙
照片墙(picture-card)
图片文件显示缩略图(URL.createObjectURL),非图片显示文件图标与文件名;点击缩略图打开预览浮层(Esc 或点击遮罩关闭),右上角 × 删除,hover 卡片出现预览/删除操作区。圆形头像卡可用 CSS 变量 --oas-upload-card-radius: 50% 达成。
触屏(pointer: coarse)下无 hover 可依赖:右上角删除×常显,失败/上传中卡片的操作遮罩常显(预览/重试/取消),删除×与操作钮触控热区扩展到 44px。
删除、预览与超限拦截
照片墙 · 删除/预览/超限
选择/拖入第 4 张时被 max="3" 拦截,触发 oas-exceed-limit 弹出警告;点击缩略图触发 oas-preview。
picture 列表带缩略图
列表带小缩略图(picture)
list / picture 模式下点击文件名同样打开预览浮层(文件名为可聚焦按钮)。
已达上限
已达 max 上限(预置满 3 张)
预置满 max="3" 后继续选择会被 oas-exceed-limit 拦截。
禁用
禁用
真实上传通道(action)
action 指定服务端地址后走内置 XHR 通道:name(表单文件字段名,默认 file)、data(附加表单字段 JSON)、headers(请求头 JSON)、method(默认 POST)、with-credentials 均透传;进度/成功/失败来自真实 XHR 事件。
action 通道(含失败重试演示)
文档站没有真实上传端点,/api/upload 返回 404,正好演示失败态:列表行转红色并出现重试按钮(⟳),点击重试重新发起请求;上传中可点 × 取消(派发 oas-cancel)。成功时派发 oas-success(detail: { file, response },response 为解析后的 JSON 或原文),失败派发 oas-error(detail: { file, response, status })。
自定义请求通道(custom-request)
分片上传、对象存储直传、WebSocket 等非标通道用 custom-request 函数 property 接管(组件不管请求策略):
custom-request 接管请求
el.customRequest = ({ file, name, action, onProgress, onSuccess, onError }) => {
// 自行发起请求,回调节奏由宿主控制
onProgress({ percent: 60 })
onSuccess({ url: 'https://example.com/f.png' }) // 或 onError({ status: 500 })
return { abort: () => {/* 取消 */} } // 可选:提供后上传中显示取消按钮
}手动上传
不加 auto-upload 即手动模式:选完文件后调用 submit()(startUpload() 的等价别名)统一提交。
手动上传(选完统一提交)
上传前校验与转换(before-upload)
before-upload 函数 property:返回 false 拒绝文件;返回新 File 转换(改名/压缩等 transform 语义);支持异步 Promise。
before-upload 校验与转换
图片裁剪(crop)
crop 开启图片上传前裁剪。生效条件:list-type 为 picture / picture-card 且 accept 包含图片类型——此时选择/拖入/粘贴图片文件不再直接入列,而是弹出内建轻量裁剪对话框(自绘浮层,零依赖):
- 移动:拖拽舞台空白处平移图像;拖拽裁剪框整体移动(聚焦后方向键微调,Shift 加速)
- 缩放框体:拖拽右下角手柄;
crop-aspect设固定宽高比(如1:1、16:9,非法/缺省为自由比例) - 缩放图像:舞台上滚轮,或工具栏放大/缩小按钮(100% = 铺满基准,上限 800%)
- 确定:离屏 canvas 按源图自然分辨率导出裁剪区域,以结果文件入列代替原图,并派发
oas-crop(detail: { file, blob }) - 取消 / Esc:不入列直接关闭;批量多选时逐张处理(取消跳过当前张、继续下一张),非图片文件不受影响直接入列
crop 裁剪后上传(picture-card + 1:1)
crop 与 before-upload 组合时先走 before-upload(含校验/转换),转换结果再进裁剪;确认入列仍受 max / max-size / replace 语义约束(裁剪结果可能比原图小,大小限制在入列时裁决)。
文件大小限制(max-size)
max-size 支持字节数或带单位写法(512KB / 2MB / 1GB);超限拒绝并派发 oas-exceed-limit(detail.type === 'size',含 maxSize 字节数)。
max-size(100KB)
超限替换(replace)
replace 开启后数量超限不再拒绝,而是移除最早的文件为新文件腾位(max=1 / 单选场景即「选新顶旧」,头像等高频场景免「先删再选」)。
replace(max=1,选择新文件自动替换)
目录与粘贴上传
directory 开启目录上传(input 落 webkitdirectory,列表显示相对路径);paste 开启粘贴上传(组件上直接 Ctrl+V 剪贴板文件,截图场景高频,默认关闭)。
目录上传(directory)
粘贴上传(paste)
触发器、提示与列表项自定义
slot="trigger":替换拖拽区内容(点击/拖拽语义保留在拖拽区容器上——zone 本身就是role="button"的可聚焦控件,内嵌内容不要再放按钮/链接等可交互元素(嵌套交互 axe 违规);展示性内容即可)tip属性或template[slot="tip"]:拖拽区下方次要说明文案(属性优先)template[slot="item"]:克隆进list/picture每行,[data-item-name]/[data-item-size]自动绑定文件名与大小
trigger / tip 插槽
item 插槽(列表行自定义)
已上传回显与隐藏列表
files/defaultFilesproperty 接受{ name, url, size? }型回显记录(状态 done,预览走远程 url),编辑场景的初值语义show-file-list="false"隐藏内置列表,只留触发区(宿主自绘预览的前提)
已上传回显(defaultFiles)
头像上传(show-file-list=false + trigger 自绘 + before-upload 校验)
事件
变化事件
监听 oas-change / oas-remove / oas-upload / oas-progress:
oas-upload:进度,detail: { file, percent, status }(status仅uploading/done;失败不在此事件,改走oas-error)oas-progress:上传进度回调(PRD P2),detail: { file, percent }——内部进度已驱动 UI,此事件补对外通道(真实 / 模拟 / custom-request 通道均派发,成功收尾派发 100)oas-success/oas-error:上传成功/失败(真实通道),detail: { file, response, status? }oas-retry/oas-cancel:重试发起 / 上传取消,detail: { file }oas-exceed-limit:超限拒绝,detail: { files, max, total }(数量)或{ files, type: 'size', maxSize, total }(大小)oas-remove:移除文件,detail: { file, index, replaced? }(replaced: true表示被replace语义替换)oas-crop:裁剪确认,detail: { file, blob }(file为原文件,blob为离屏 canvas 裁剪结果)
方法:submit()(手动上传)、startUpload()(等价)、abort(file?)(取消单个/全部进行中的上传)。
oas-progress 进度反馈
第三方组合场景
以下场景不进组件 API,经既有通道组合达成:
// 大文件分片 / 对象存储直传:custom-request 接管(分片策略是业务决策)
el.customRequest = async ({ file, onProgress, onSuccess, onError }) => {
const chunks = sliceFile(file, 5 * 1024 * 1024) // 自行分片
for (let i = 0; i < chunks.length; i++) {
await uploadChunk(chunks[i], i)
onProgress({ percent: ((i + 1) / chunks.length) * 100 })
}
onSuccess(await assembleChunks(file))
}- 头像裁剪:内建
crop通道覆盖(见「图片裁剪」节);需接第三方裁剪库时可改用before-upload返回裁剪后的新File - 上传列表拖拽排序:
item插槽自定义行 + 宿主接第三方 dnd 库重排files - 圆形头像卡:CSS 变量
--oas-upload-card-radius: 50%(不占独立枚举)
required 必填
required 必填(原生校验链)
required 驱动原生校验链(form-associated):未填时 checkValidity() 为 false(valueMissing),原生表单提交被阻止;填写后自动恢复 :valid。
当前表单值可经公开 value property 读/写:el.value 返回可提交的 File 数组({name,url} 回显记录无文件体、不计入),无文件时为空数组;el.value = [file] 整体替换文件列表(走 files property 同款受控通道,不派发事件)。
API
oas-upload
属性
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
accept | 接受的文件类型 | string | — |
action | 上传接口 URL(真实 XHR 通道;不配且无 customRequest 时为模拟进度) | string | — |
auto-upload | 添加后自动模拟上传 | boolean | — |
crop | 图片上传前裁剪(picture/picture-card + accept 含图片时生效):选择后弹内建裁剪对话框,确认以 canvas 裁剪结果入列 | boolean | — |
crop-aspect | 裁剪固定宽高比(如 1:1、16:9);非法/缺省为自由比例 | string | — |
data | 附加表单字段(JSON 字符串,随文件一起提交) | — | — |
directory | 目录上传(整目录递归入列) | boolean | — |
disabled | 禁用 | boolean | — |
headers | 附加请求头(JSON 字符串) | — | — |
list-type | 列表样式:list(默认)/ picture(列表带小缩略图)/ picture-card(卡片缩略图墙) | string | list |
max | 最大文件数 | string | 0 |
max-size | 单文件大小上限(字节或 2KB/1MB/1GB;超限派 oas-exceed size 形态) | string | — |
method | HTTP 方法(默认 POST) | string | POST |
multiple | 多选 | boolean | — |
name | 上传文件的表单字段名(默认 file) | string | — |
paste | 粘贴上传(默认关;开启后粘贴剪贴板文件入列) | boolean | — |
replace | max-count=1 时替换语义(新文件替换旧文件而非拒绝) | boolean | — |
required | 必填标记(驱动原生校验链 valueMissing;不透传内层控件) | boolean | — |
show-file-list | 文件列表显隐("false" 隐藏,仅保留拖拽区) | string | true |
tip | 拖拽区提示文案(同 template[slot="tip"] 富内容) | string | — |
with-credentials | 跨域携带凭证 | boolean | — |
Property(JS property;是否写回 attribute 见各行说明)
| Property | 说明 | 类型 | 默认值 |
|---|---|---|---|
files | 受控文件列表(property 通道,写回即同步渲染) | Array<File | UploadEchoFile> | [] |
value | 当前值:可提交的 File[](仅文件体条目;回显记录不含文件体、不计入) | File[] | null | [] |
事件
| 事件 | 说明 |
|---|---|
oas-cancel | 取消上传,detail: { file }(行/卡片 cancel 按钮) |
oas-change | 文件列表变化,detail: { files } |
oas-crop | 裁剪确认时派发,detail: { file, blob }(file 原文件,blob 裁剪结果) |
oas-error | 上传失败,detail: { file, response?, status? }(行/卡片出重试按钮) |
oas-exceed | 【兼容别名】等价 oas-exceed-limit;后续版本移除,detail: { files: rejected, max, total: next.length } | { files: sizeRejected, type: 'size', maxSize, total: next.length } |
oas-exceed-limit | 添加文件超限被拒绝(规范名,对齐 checkbox-group/select/toggle-group),detail: { files, max, total };数量/大小超限均派发(大小超限额外带 type: 'size' 与 maxSize) |
oas-preview | 打开预览浮层,detail: { file, url } |
oas-progress | 上传进度回调,detail: { file, percent }(真实/模拟/custom-request 均派发,成功收尾 100) |
oas-remove | 移除文件,detail: { file, index } |
oas-retry | 点击重试,detail: { file }(失败后重发) |
oas-success | 上传成功,detail: { file, response } |
oas-upload | 上传进度,detail: { file, percent, status } |
插槽
| 名称 | 说明 |
|---|---|
template[slot="item"] | 自定义文件行/卡片([data-item-name]/[data-item-size] 绑定) |
template[slot="tip"] | 拖拽区提示富内容(tip 属性优先) |
template[slot="trigger"] | 自绘触发区模板(native slot 对 template 元素不生效,走克隆通道;zone 点击仍打开文件选择) |
trigger | 替换拖拽区内容(zone 语义保留) |
CSS 变量
| CSS 变量 | 默认值 |
|---|---|
--oas-upload-card-radius | var(--oas-radius-md) |
⚠️
template[slot="trigger"]的三个限制:① 模板内容克隆进 shadow DOM——宿主页面样式表对克隆内容不生效(样式用内联样式 / oas 组件 / CSS 变量解决);② 克隆是组件 update() 时的静态快照——模板连接后再变更不会自动刷新(写完模板再挂组件,或之后改任意属性触发一次 update 重同步);③cloneNode不携带事件监听器——宿主绑在模板节点上的@click/addEventListener在克隆里失效,交互请走组件事件(oas-change等)或在克隆后的 zone 容器上委托绑定。
键盘:拖拽区 Enter / 空格 打开文件选择;删除按钮可聚焦;预览浮层 Esc 关闭。