SwUploadVideo 是视频文件的分片上传组件。它将上传逻辑完全交由调用方通过 uploadFn 和 queryFn
两个 Props 注入,自身不预设任何接口地址,适配任意后端协议。
上传完成后可选择是否通过 queryFn 轮询转码结果(pollVideo 控制)。组件通过默认 slot
暴露当前状态,支持完全自定义触发区域 UI,包括拖拽上传。
基础用法(按钮式)
最简用法:按钮触发选视频 → 分片进度 → 转码轮询 → 完成后给出可播放预览。
基础用法(按钮 + 进度 + 可播放预览)
加载中...
<!-- accept 限定格式(默认 'video/*');multiple 允许多选——
每个文件独立走「上传 + 转码轮询」,逐个 emit @success -->
<SwUploadVideo
v-slot="{ open, pending }"
:upload-fn="chunkUpload"
:query-fn="queryVideo"
accept="video/mp4"
multiple
@success="(r) => list.push(r)"
>
<SwButton :disabled="pending" @click="() => open()">批量上传视频</SwButton>
</SwUploadVideo>
自定义触发区(#default slot)
「+ 号上传卡」:默认 slot 完全接管触发区 UI,上传 / 转码进度直接画在卡内。
+ 号上传卡(slot 自定义)
加载中...
拖拽上传
slot 的 isOver 状态可以高亮拖拽区域;进度条 + 转码等待提示也由 slot 自绘。
拖拽 + 进度 + 转码轮询
加载中...
不轮询转码(pollVideo=false)
仅需获取分片上传成功的原始结果(ChunkSuccess),不等待转码完成时使用。
不等转码(ChunkSuccess 即返回)
加载中...
错误处理
分片失败(重试耗尽)时触发 error 事件。
分片失败反馈(@error)
加载中...
受控列表(fileList + #file + maxCount + beforeUpload)
传 v-model:file-list 后组件接管已传列表:成功结果自动追加、#file 插槽逐条渲染预览与删除;maxCount 控制数量上限(超限整批拒绝并 emit exceed)、beforeUpload 做逐文件前置校验(体积 / 重名 / 类型,返回 false 剔除)。这是迁移老项目多文件上传(预览 + 删除 + limit + 校验)的完整形态。
<template>
<SwUploadVideo
v-model:file-list="videos"
:upload-fn="chunkUpload"
:query-fn="queryVideo"
:max-count="3"
:before-upload="(f) => f.size <= maxSize || (useToast().warning('视频过大'), false)"
multiple
@exceed="useToast().warning('最多上传 3 个视频')"
>
<template #default="{ open, pending, progress }">
<SwButton :loading="pending" @click="open">
{{ pending ? `上传中 ${progress}%` : '选择视频' }}
</SwButton>
</template>
<template #file="{ file, remove }">
<span>{{ file.id }} <SwButton aria-label="删除" @click="remove">✕</SwButton></span>
</template>
</SwUploadVideo>
</template>
Props
| 名称 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
uploadFn | (_files: File[], _options: VideoUploadOptions) => void | ✓ | — | 分片上传函数 |
queryFn | (_id: string, _retries?: number) => Promise<VideoQueryResult> | ✓ | — | 转码结果查询函数 |
accept | string | 'video/*' | 文件选择 accept | |
chunkSize | number | 2097152(2 MB) | 分片大小(字节) | |
retries | number | 3 | 单片重试次数 | |
multiple | boolean | false | 是否允许多文件 | |
pollVideo | boolean | true | 上传完成后是否轮询转码结果 | |
fileList | ChunkSuccess | VideoQueryResult[] | undefined | 已传文件受控列表(v-model:file-list)。传入后成功结果自动追加,配合 #file 插槽渲染预览 + 删除;不传保持"单次上传薄壳"行为 | |
maxCount | number | undefined | 文件数量上限(含 fileList 现有计数)。选择超限时整批拒绝并 emit exceed | |
beforeUpload | (file: File, batch: File[]) => boolean | Promise<boolean> | undefined | 逐文件前置否决钩子:返回 false 剔除该文件(其余照传,全剔则本批终止)。体积 / 重名 / 自定义校验与用户提示都在钩子里做 |
类型定义
VideoUploadOptions
interface VideoUploadOptions {
chunkSize?: number
retries?: number
onProcess?: (result: ChunkProgress) => void
onSuccess?: (result: { id: string; file_md5: string; file: File }) => void
onError?: (result: { file: File; error: unknown }) => void
onBefore?: (file: File) => void
}
interface ChunkProgress {
file: File
processed_num: number
chunk_total: number
chunk_index: number
file_md5: string
}
VideoQueryResult
interface VideoQueryResult {
id: string
file_m3u8: string
file_duration: string
file_preview_m3u8: string
file_status: string
width: number
height: number
}
Events
| 事件名 | 载荷类型 | 说明 |
|---|---|---|
progress | pct: number | 上传进度百分比(0-100) |
success | result: ChunkSuccess | VideoQueryResult | pollVideo=true 时 VideoQueryResult(转码完);pollVideo=false 时 ChunkSuccess(仅分片上传完) |
error | err: Error | 上传或转码错误 |
update:fileList | ChunkSuccess | VideoQueryResult[] | 受控列表变化(成功追加 / remove() 移除),携带新列表 |
remove | (file: ChunkSuccess | VideoQueryResult, index: number) | #file 插槽的 remove() 被调用 |
exceed | File[] | 选择文件数超出 maxCount,携带本次选择的文件(本批已被整体拒绝) |
Slots
default(作用域 slot)
| 作用域变量 | 类型 | 说明 |
|---|---|---|
isOver | boolean | 文件正在拖拽悬停区域上方 |
pending | boolean | 上传或轮询进行中 |
progress | number | 当前上传进度(0–100) |
open | () => void | 手动触发文件选择对话框 |
file | { file, index, remove } | 传了 fileList 时对列表逐条渲染(预览 / 删除按钮由消费方自绘);remove() 从列表移除该条并 emit remove |
注意事项
uploadFn和queryFn均为必填,需由业务层自行实现并传入。chunkSize默认 2MB(2097152 字节),需与后端约定保持一致。pollVideo=true时,success事件将在转码完成后才触发,结果类型为VideoQueryResult。pollVideo=false时,success在分片上传完成后立即触发,结果为{ id, file_md5, file }。