yuuki-uploader-vue
v1.0.3
Published
vue3实现的大文件分片上传器
Readme
Yuuki-Uploader
文件上传器,实现了文件分片上传、分片检测、断点续传等功能。
采用 hooks 设计方式,分别使用 React 和 Vue3 实现。
安装
使用 vue 版本运行
npm install yuuki-uploader-vue使用 react 版本运行
npm install yuuki-uploader-react基本用法
上传流程简述
在文件添加时,会先计算文件的 MD5 值(Spark-MD5实现),此时文件状态为calculating,在 MD5 值计算完成后,文件进入waiting状态
使用 upload 方法即可使waiting状态的文件其进入uploading状态,upload 方法调用时,首先会发送预检请求(POST 请求),根据 http 状态码决定后续是否上传。在实际文件块上传之前,会先发送不带有文件块的测试请求(GET 请求),同样根据 http 状态码决定是否实际上传请求(POST 请求)
所有分块上传完毕后,文件进入complete状态,此时发送合并请求(POST 请求),根据 http 状态码决定上传是否成功,上传成功则进入success状态
文件暂停时会进入pause状态,使用 resume 方法恢复时,会重新发送所有的测试请求(GET 请求),确定还未发送的文件块
上述任何一个环节出现问题,文件都会进入fail状态
默认请求成功的状态码(预检和测试请求后会实际上传): 200, 201, 202
默认跳过上传的状态码(预检和测试请求后不会实际上传): 204, 205, 206
默认上传失败的状态码(上传器终止所有与失败文件相关的请求): 400, 404, 415, 500, 501
其它状态码和网络错误等: 上传器会尝试重传直到达到重传次数上限
请求中的基本数据
所有请求都会包含文件的基本信息,如下图 FileInformation 所示
interface FileInformation {
totalChunks: number //总块数
chunkSize: number //预设分块标准大小
filename: string //文件名
totalSize: number //总文件大小
hash: string //文件md5
webkitRelativePath: string //上传文件夹时文件路径
}分块相关的请求会携带分块相关的一些数据,如下图所示
interface TestChunk extends FileInformation {
chunkIndex: number //当前块号
currentSize: number //当前块大小
}
interface Chunk extends TestChunk {
file: Blob //文件流
}Uploader 构造函数
两个版本的都通过 useUploader 函数返回一个 Uploader 对象
const useUploader = (uploaderOption?: Partial<UploaderOption>): Uploader其中,Vue 版本和 React 版本在数据响应式和注册上传器方面存在一定差异,其余部分一致
Vue 版本 Uploader
export interface Uploader {
uploadList: ComputedRef<UploadFile[]> //响应式文件列表
register: (element: Ref<HTMLElement | undefined>) => void //将元素注册为可点击上传文件
registerDrop: (element: Ref<HTMLElement | undefined>) => void //将元素注册为拖拽上传区域
addFile: (rawFile: File) => Promise<void> //添加单个文件
addFileList: (fileList: File[]) => Promise<void> //添加多个文件
removeFile: (uploadFile: UploadFile) => void //移除单个文件
unRegister: () => void //解除注册元素的点击上传功能
unRegisterDrop: () => void //解除注册元素的拖拽上传功能
upload: (uploadFile: UploadFile) => void //上传指定的文件
pause: (uploadFile: UploadFile) => void //暂停指定的文件
cancel: (uploadFile: UploadFile) => void //取消指定文件的上传
resume: (uploadFile: UploadFile) => void //恢复指定文件的上传
uploadAll: () => void //上传文件列表中所有waiting状态的文件
pauseAll: () => void //暂停文件列表中所有uploading状态的文件
cancelAll: () => void //取消上传所有uploading和pause状态的文件
}React 版本的 Uploader
export interface Uploader {
uploadList: UploadFile[] //响应式文件列表
register: (element: RefObject<HTMLElement>) => void //将元素注册为可点击上传文件
registerDrop: (element: RefObject<HTMLElement>) => void //将元素注册为拖拽上传区域
addFile: (rawFile: File) => Promise<void> //添加单个文件
addFileList: (fileList: File[]) => Promise<void> //添加多个文件
removeFile: (uploadFile: UploadFile) => void //移除单个文件
unRegister: () => void //解除注册元素的点击上传功能
unRegisterDrop: () => void //解除注册元素的拖拽上传功能
upload: (uploadFile: UploadFile) => void //上传指定的文件
pause: (uploadFile: UploadFile) => void //暂停指定的文件
cancel: (uploadFile: UploadFile) => void //取消指定文件的上传
resume: (uploadFile: UploadFile) => void //恢复指定文件的上传
uploadAll: () => void //上传文件列表中所有waiting状态的文件
pauseAll: () => void //暂停文件列表中所有uploading状态的文件
cancelAll: () => void //取消上传所有uploading和pause状态的文件
}Tips: React 版本返回的 uploadList 使用 useState 实现的状态变量,你无需维护该属性,它会自动实现响应式更新
UploaderOption 配置项
在初始化时,你可以通过填入不同的配置项自定义 Uploader
export interface UploaderOption {
accept: string //接受的文件类型,与input标签的accept功能相同,默认为''
multiple: boolean //文件多选(multiple实现),默认为true
directoryMode: boolean //选择文件夹上传(multiple失效),默认为false
chunkSize: number //分块大小(byte),默认为2*1024*1024
target: string //分块上传目标url,默认为'/'
mergeTarget: string //合并请求目标url,默认为'/'
precheckTarget: string //预检请求目标url,默认为'/'
concurrency: number //请求最大并发数量,默认为3
headers: Record<string, string> //自定义请求头,默认为{}
withCredentials: boolean //是否携带凭证,默认为false
retryCount: number //失败重试次数,默认为3
progressCallbacksInterval: number //progress回调函数最小间隔(ms),默认200
successCodes: number[] //认为是上传成功的状态码(测试和预检请求后会发送实际上传请求),默认为[200,201,202]
skipCodes: number[] //认为是文件或分块已存在的状态码(测试和预检请求后不再发送实际上传请求),默认为[204,205,206]
failCodes: number[] //认为是上传失败的状态码(不会再重新发送和失败文件相关的任何请求),默认为[400, 404, 415, 500, 501]
data?: (uploadFile: Readonly<UploadRawFile>) => Record<string, string | number> //测试分块和上传分块请求中发送的自定义数据
mergeData?: (uploadFile: Readonly<UploadRawFile>) => Record<string, any> //合并请求中发送的自定义数据
precheckData?: (uploadFile: Readonly<UploadRawFile>) => Record<string, any> //预检请求中发送的自定义数据
}Uploader 监听事件
导出了 EventHandler 类型提供监听事件的定义,但使用时仍然定义在 UploaderOption 中(UploaderOption 类型包含了 EventHandler 类型)
export interface EventHandler {
// 拖拽相关事件
onDragEnter?: (event: DragEvent) => void //文件进入拖拽区域调用
onDragOver?: (event: DragEvent) => void //文件在拖拽区域中反复调用
onDragLeave?: (event: DragEvent) => void //文件离开拖拽区域中调用
//文件相关事件
onFileAdded?: (file: File) => Awaitble<boolean | void> //文件添加前调用(支持返回Promise)
onFileReady?: (file: UploadFile) => Awaitble<void> //文件计算完成准备就绪后调用
onFileRemoved?: (file: UploadFile) => void //文件被移除后调用
onFileStart?: (file: UploadFile) => void //文件开始上传时调用
onFileProgress?: (file: UploadFile) => void //文件上传中调用
onFilePause?: (file: UploadFile) => void //文件暂停时调用
onFileCancel?: (file: UploadFile) => void //文件被取消后调用
onFileComplete?: (file: UploadFile) => void //文件所有分块上传成功后调用
onFileSuccess?: (file: UploadFile) => void //文件上传成功后调用
onFileFail?: (file: UploadFile, error: Error) => void //文件上传失败后调用
}
type Awaitble<T> = T | Promise<T>UploadFile
响应式文件列表中维护的文件的类型
export interface UploadFile {
uid: number //文件uid
name: string //文件名,同原生文件名
size: number //文件大小,同原生文件大小
type: string //文件类型,同原生文件类型
progress: number //文件进度,0~100保留一位小数
currentSpeed: number //文件瞬时速度(单位bytpe/s)
averageSpeed: number //文件平均速度(单位bytpe/s)
status: UploadStatus //文件状态
raw: UploadRawFile //内部API使用的文件对象
}
export type UploadStatus =
| 'calculating'
| 'waiting'
| 'uploading'
| 'compelete'
| 'pause'
| 'success'
| 'fail'简单示例
源代码中提供了简单的上传示例,clone 代码并运行pnpm install后,可以运行pnpm dev:vue或pnpm dev:react启动 vue 示例或 react 示例,同时需要运行pnpm dev:server启动 node.js 示例服务。
作者附
写了好几个版本的,还是垃圾的没法看,路还是很漫长啊!
