@hife/uploader
v2.0.1
Published
## Install ```shell yarn add @hife/uploader ```
Downloads
21
Readme
Web 端文件上传
Install
yarn add @hife/uploader
Example
# 1. 首先 clone 本仓库
git clone [email protected]:hifeteam/uploader.git
# 2. 进入项目安装依赖
cd uploader && yarn
# 3. 开启 node 服务,模拟后端接收请求;也可以修改 server/index.js,自行控制上传请求的响应数据
npm run server
# 4. 开启 storybook 开发环境,查看示例
npm start
API
const uploadOptions = {
// ...
}
const uploader = new Webuploader(uploadOptions)
1. uploadOptions
import { Canceler } from 'axios';
export interface UploadOptions {
/**
* input dom
*/
dom: HTMLInputElement | HTMLInputElement[];
/**
* 是否可以选择多个文件
* 默认值:false
*/
multiple?: boolean;
/**
* 上传文件的地址
*/
url: string;
/**
* 上传分片的地址(若不指定,则使用 url 作为分片上传的地址)
*/
uploadChunkUrl?: string;
/**
* 文件上传方式
* 默认值:'post'
*/
method?: MethodType;
/**
* 接受的文件类型
* 默认值:'*/*'
* 值参照:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#attr-accept
* 支持只传文件后缀作为接受的类型
*/
accept?: string;
/**
* 文件的最大大小,单位:B
*/
maxSize?: number;
/**
* 文件的最大数量
*/
maxCount?: number;
/**
* 是否开启分片上传
* 默认值:false
*/
chunked?: boolean;
/**
* 分片大小,单位:MB
* 默认值:1
*/
chunkSize?: number;
/**
* 开启分片上传的阈值,单位:MB(文件大小小于该值的时候,不进行分片上传;没有提供值时且开启分片上传时,则所有文件都进行分片上传)
* 默认值:0
*/
chunkThreshold?: number;
/**
* 是否选择文件后就自动开始上传
* 默认值:true
*/
autoUpload?: boolean;
/**
* 上传并发数
* 默认值:1
*/
threads?: number;
/**
* 上传文件出错时自动重试的次数
* 默认值:2
*/
retryCount?: number;
/**
* 上传分片出错时自动重试次数的次数
* 默认值:2
*/
chunkRetryCount?: number;
/**
* 文件是否需要 md5 序列化
* 默认值:false
*/
md5?: boolean;
/**
* 分片是否需要 md5 序列化
* 默认值:false
*/
chunkMD5?: boolean;
/**
* 文件筛选函数,返回值为通过筛选的文件
*/
filter?: FilterFunction;
/**
* 文件排序函数,返回值为排好序的文件
*/
sort?: FilterFunction;
/**
* 校验完文件(maxSize/maxCount)的回调
*/
onVerified?: OnVerifiedFn;
/**
* 有新的文件被加入队列时的回调
* filesInfo:被加入到队列的文件信息
*/
onFilesInfoQueued?: (filesInfo: FileInfo[]) => void;
/**
* 文件数量改变、文件状态改变时的回调
* allFileInfo:所有上传的文件信息
* statusChangedFileInfo:状态发生的文件信息
*/
onChange?: (
allFileInfo: FileInfo[],
statusChangedFileInfo?: FileInfo
) => void;
/**
* 上传前的回调,此回调用来对文件进行 md5 序列化、验证等操作
* fileInfo:文件信息
* callback:回调函数。当传入 errorMessage 参数,表示有错误,该文件不进行上传;否则进行上传
*/
onBefore?: (
fileInfo: FileInfo,
callback: (errorMessage?: string) => void
) => void;
/**
* 开始上传的回调
* fileInfo:文件信息
*/
onStart?: (fileInfo: FileInfo) => void;
/**
* 文件是否上传成功的验证回调(可使用此回调对服务端返回的数据进行验证,看是否真的上传成功了)
* fileInfo:文件信息
* res:服务端响应的数据
* callback:回调函数。当传入 errorMessage 参数,表示有错误,该文件上传是否;否则文件上传成功
*/
onSuccessVerify?: (
fileInfo: FileInfo,
res: unknown,
callback: (errorMesssage?: string) => void
) => void;
/**
* 上传成功的回调
* fileInfo:文件信息
* res:服务端响应的数据
*/
onSuccess?: (fileInfo: FileInfo, res?: unknown) => void;
/**
* 上传失败的回调
* error:错误信息
* info:上传失败的文件(分片)信息
*/
onError?: (error: Error, info: Info) => void;
/**
* 文件上传失败时重试的回调
* fileInfo:文件信息
* res:服务端响应的数据
*/
onRetry?: (fileInfo: FileInfo, res?: unknown) => void;
/**
* 上传后的回调(成功或者失败)
* fileInfo:上传后的文件信息
*/
onAfter?: (fileInfo: FileInfo) => void;
/**
* 上传分片前的回调,此回调用来验证是否可以进行上传
* chunkInfo:分片信息
* callback:回调函数。当传入 errorMessage 参数,表示有错误,该文件不进行上传;否则进行上传
*/
onChunkBefore?: (
chunkInfo: ChunkInfo,
callback: (errorMessage?: string) => void
) => void;
/**
* 开始上传分片的回调
* chunkInfo:分片信息
*/
onChunkStart?: (chunkInfo: ChunkInfo) => void;
/**
* 分片是否上传成功的验证回调(可使用此回调对后端返回的数据进行验证,看是否真的上传成功了)
* chunkInfo:分片信息
* res:服务端响应的数据
* callback:回调函数。当传入 errorMessage 参数,表示有错误,该分片上传是否;否则分片上传成功
*/
onChunkSuccessVerify?: (
chunkInfo: ChunkInfo,
res: unknown,
callback: (errorMesssage?: string) => void
) => void;
/**
* 上传分片成功的回调
* chunkInfo:分片信息
* res:服务端响应的数据
*/
onChunkSuccess?: (chunkInfo: ChunkInfo, res: unknown) => void;
/**
* 上传分片失败的回调
* error:错误信息
*/
onChunkError?: (error: Error) => void;
/**
* 分片上传失败时重试的回调
* chunkInfo:分片信息
* res:服务端响应的数据
*/
onChunkRetry?: (chunkInfo: ChunkInfo, res?: unknown) => void;
/**
* 上传分片后的回调(成功或者失败)
* chunkInfo:分片信息
*/
onChunkAfter?: (chunkInfo: ChunkInfo) => void;
/**
* 一个文件的所有分片都上传完成的回调
* uploadedFileInfo:文件信息
* callback:回调
* callbackParams:回调参数
* errorMessage:当传入 errorMessage 参数,表示有错误,该文件上传失败;否则表示上传成功
* isRetry:是否对该文件进行上传重试。可选,默认值:true
* fileInfo:文件信息。必传
* res:服务端返回的数据。必传
*/
onChunkComplete?: (
uploadedFileInfo: FileInfo,
callback: (callbackParams: {
// errorMessage 存在时,说明出错了
errorMessage?: string;
isRetry?: booelan;
fileInfo: FileInfo;
res: unknown;
}) => void
) => void;
/**
* 所有文件上传完成的回调
* uploadedFiles:已上传成功的文件信息
*/
onComplete?: (uploadedFiles: Array<FileInfo>) => void;
/**
* 上传进度改变的回调
* totalProgress:总进度
* filesInfo:所有的文件信息
*/
onProgress?: (totalProgress: number, filesInfo: FileInfo[]) => void;
/**
* 请求适配器
*/
requestAdapter?: RequestAdapterType;
}
export type MethodType = 'post' | 'get';
// 文件(分片)上传的状态:'等待上传' | '正在上传' | '完成上传' | '出错' | '无效'
export type UploadStatus =
| 'waiting'
| 'uploading'
| 'uploaded'
| 'error'
| 'invalid';
export interface FileInfo {
[key: string]: any;
id: string; // 文件 id
type: 'file'; // 类型,'file' 表示属于文件
file: File; // 文件
chunks?: Array<ChunkInfo>; // 文件的分片
index: number; // 索引
md5?: string; // 文件 md5 值
retryCount: number; // 剩余重试次数
progress: number; // 上传进度
status: UploadStatus; // 上传状态
cancel?: Canceler; // 取消 ajax 请求的函数
loaded: number; // 已上传的数据量,单位:B
}
export interface ChunkInfo {
[key: string]: any;
id: string; // 分片 id
type: 'chunk'; // 类型,'chunk' 表示属于分片
belongFile: FileInfo; // 分片所属文件的信息
chunk: Blob; // 分片
md5?: string; // 分片的 md5 值
index: number; // 索引
retryCount: number; // 剩余重试次数
status: UploadStatus; // 上传状态
cancel?: Canceler; // 取消 ajax 请求的函数
loaded: number; // 已上传的数据量,单位:B
}
export type Info = FileInfo | ChunkInfo;
export interface FilterFunction {
(files: File[]): File[];
}
// verifiedParams:校验后的参数。当 verifiedParams 为 undefined 时,表示校验没有问题
export type OnVerifiedFn = (verifiedParams?: {
// 验证未通过的类型:
// 'MAX_SIZE' 表示有文件未通过 maxSize 的验证
// 'MAX_COUNT' 表示有文件未通过 maxCount 的验证
// 'ACCEPT' 表示有文件未通过 accept 的验证(在 firefox 中 accept 有 bug)
type: 'MAX_SIZE' | 'MAX_COUNT' | 'ACCEPT';
files: File[]; // 未通过验证的文件信息
}) => void;
2. uploader 实例方法
/**
* 添加对 input change 事件的监听(当你想用另外一个 file input 选择文件且不想创建新实例时使用。此时新的 file input 选择的文件也处于原来的文件列表中)
*/
uploader.addInputDOM: (HTMLInputElement | HTMLInputElement[]) => void;
/**
* 获取文件统计信息
*/
uploader.getStats: () => any;
/**
* 清除文件统计数据
*/
uploader.clearStats: () => any;
/**
* 将一个文件(分片)设置为成功上传的状态
* id:文件(分片)的 id
*/
uploader.toSuccessful: (id: string) => void;
/**
* 通过 id 移除一个文件。移除成功返回 true,移除失败返回 false
* id:文件的 id
*/
uploader.remove: (id: string) => boolean;
/**
* 对一个文件(分片)进行重试上传。返回值为 true 时,表示正在重试;否则表示没有重试次数了,不进行重试
* id:文件(分片)的 id
*/
uploader.retry: (id: string) => boolean;
/**
* 移除对 input change 事件的监听
* 注意:在第二次(包含第二次)之后对同一个 input 实例化时,需要先调用方法
*/
uploader.removeEventListener: () => void;
3. 自定义 Request Config
webuploader 使用的是 axios
请求库进行文件上传。有时我们需要修改请求时的一些 选项 来实现一些功能,比如说:
- 配置
withCredentials
为true
,实现在跨域请求时带上cookie
此时可以使用下面的方法,对 axios
的 Reqeust
进行配置
import { Webuploader, axiosAdapterFactory } from '@hife/uploader';
Webuploader.configure({
requestAdapter: axiosAdapterFactory({
withCredentials: true
})
});
export default Webuploader;
- 以上配置了一次之后,在别处引用都生效
⚠️ 注意
如果你的项目中也使用了 axios,可能会存在项目中 axios 的全局配置会影响 axiosAdapter 的配置,导致出现 bug
Todolist
- [ ] 部署 storybook 到 github page,且能够正常查看例子
- [ ] 测试覆盖率达到 100%
- [ ] uploader.start():开始上传
- [ ] uploader.pause():暂停上传