Uploader 上传
Uploader 组件用于图片或文件的上传。
详情列表
将list-type属性设置为details,显示文件详情列表。
图片列表
将list-type属性设置为image-card,显示图片列表。
自定义文件获取方式
默认情况下,用户点击上传按钮后通过 h5 选择文件。通过file-picker-items属性可以传入一个文件选取方式列表,为用户提供多种文件选取方式。
手动上传
将auto-upload属性设置为false,选择文件后不会立即上传,调用组件的uploadFiles方法后才会开始上传。
自定义上传方法
通过传入action、method、data等属性可以使用组件本身提供的上传功能,也可以通过custom-upload-method属性传入自定义的上传方法,自己实现将文件上传到后端的方法。
上传前校验
组件本身不会向用户提示上传前校验所发现的问题,可以通过on-validate回调方法来获取上传前校验的结果并向用户进行提示。
类型
typescript
/**
* 文件读取的结果类型
* @description 值为`file`时返回文件的`File`对象,值为`dataUrl`时返回文件对应的base64编码
*/
export type FileReadType = 'file' | 'dataUrl';
export type HttpMethod =
| 'POST'
| 'GET'
| 'PUT'
| 'OPTION'
| 'PATCH'
| 'post'
| 'get'
| 'put'
| 'option'
| 'patch';
/**
* 文件条目
*/
export interface FileItem {
/** 文件名称 */
name?: string;
/** 原始文件对象 */
rawFile?: File;
/** base64格式的文件内容 */
dataUrl?: string;
/** 原始文件的MIME类型 */
type?: string;
/** 文件的大小 (Bytes) */
size?: number;
/** 上次修改时间 */
lastModified?: number;
}
/**
* 上传文件条目
*/
export interface UploadFileItem extends FileItem {
/**
* 文件名称
* @description 根据文件的后缀名判断文件类型
*/
name?: string;
/** 文件的预览图片的地址 */
thumbnailUrl?: string;
/** 文件的下载地址 */
url?: string;
/** 文件的上传时间 */
uploadTime?: string;
/** 文件的大小 (Bytes) */
size?: number;
/**
* 文件上传状态
* @description 上传成功、上传失败、上传中、等待上传
*/
status?: 'success' | 'fail' | 'progress' | 'waiting';
/**
* 文件上传进度
* @description 上传进度百分比,[0, 100]
*/
percent?: number;
/**
* 文件ID
* @description 用于在文件名称重复时唯一标识一个文件,允许为空
*/
id?: string;
/** 用户自定义的上下文数据 */
[key: string]: any;
}
/**
* 文件上传进度变更信息
*/
export interface UploadProgressContext {
/** 上传进度类型 */
type: 'real' | 'mock';
/**
* 相关文件
* @description 如果单请求上传多个文件,则长度大于一
*/
files: UploadFileItem[];
/** 百分比进度值 */
percent: number;
[key: string]: any;
}
/**
* 上传请求响应数据
* @description 后端上传接口响应的数据
*/
export interface UploadResponseData {
/**
* 错误信息
* @description 如果本字段非空,则认为文件上传失败了
*/
error?: string;
/**
* 上传后的文件访问地址
* @description 将被赋值给对应文件的`url`字段(单请求上传多个文件`singleRequestUpload=true`时无效)
*/
url?: string;
/**
* 上传后的文件缩略图地址
* @description 将被赋值给对应文件的`thumbnailUrl`字段(单请求上传多个文件`singleRequestUpload=true`时无效)
*/
thumbnailUrl?: string;
[key: string]: any;
}
/**
* 单个文件上传结果的上下文
*/
export interface UploadResponseContext {
/**
* 上传的文件
*/
file: UploadFileItem;
/**
* 是否上传成功
*/
success: boolean;
/**
* 上传请求的响应数据
* @description 如果是单请求上传多个文件的模式(`singleRequestUpload=true`时),则该字段为空
*/
responseData?: UploadResponseData;
}
/**
* 自定义文件上传上下文
* @description 当用户自定义文件上传方法时,可以通过本上下文中的回调方法通知文件的上传状态
*/
export interface CustomUploadFileContext {
/** 待上传的文件 */
file: UploadFileItem;
/**
* 更新上传进度回调
* @description 用于更新当前文件的上传进度
*/
onProgress: (e: { percent: number } & Record<string, any>) => void;
/**
* 上传成功回调
* @description 文件上传成功后回调,允许将请求响应数据作为参数
*/
onSuccess: (e?: UploadResponseData) => void;
/**
* 上传失败回调
* @description 文件上传失败后回调,允许将请求响应数据作为参数
*/
onFail: (e?: UploadResponseData) => void;
}
export interface UploadResult {
/**
* 单请求多文件上传的响应数据
* @description 上传请求的响应数据,仅当单请求上传多个文件`singleRequestUpload=true`时非空
*/
responseData?: UploadResponseData;
/**
* 上传成功的文件及其响应数据
* @description 如果没有文件上传成功,则为空
*/
successItems?: UploadResponseContext[];
/**
* 上传失败的文件及其响应数据
* @description 如果没有文件上传失败,则为空
*/
failedItems?: UploadResponseContext[];
}
/**
* 内建的列表样式
* @description `文件详情列表`或者`图片列表`
*/
export type UploaderListType = 'details' | 'image-card';
/**
* 文件选取参数
*/
export interface FilePickerOption {
/**
* 接受上传的文件类型
* @description 默认不限制
*/
accept?: string;
/**
* 是否启用文件多选
* @description 是否允许用户一次选择多个文件
*/
multiple?: boolean;
/**
* 文件读取的结果类型
* @description 用户选择的文件将被转化为本字段所指定的格式
*/
fileReadType?: FileReadType;
/** 单个文件的大小限制 (Bytes) */
maxSize?: number;
/**
* 最大文件数量
* @description 最多可以上传多少个文件
*/
maxCount?: number;
/**
* 已上传文件的数量
* @description 已经上传了多少个文件,用`maxCount - uploadedFileCount`可以得到还能上传的最大文件数量
*/
uploadedFileCount?: number;
[key: string]: any;
}
/**
* 上传组件上下文
* @description 组件的相关属性,只读
*/
export interface UploaderContext extends FilePickerOption {
/** 文件列表的内建样式 */
listType?: UploaderListType;
/** 组件是否处于只读状态 */
readonly?: boolean;
/** 组件是否处于禁用状态 */
disabled?: boolean;
/** 接受上传的文件类型 */
accept?: string;
/** 是否启用文件多选 */
multiple?: boolean;
/** 文件读取的结果类型 */
fileReadType?: FileReadType;
/** 单个文件的大小限制 (Bytes) */
maxSize?: number;
/** 最大文件数量 */
maxCount?: number;
/** 已上传文件的数量 */
uploadedFileCount?: number;
/** 当前显示的文件列表 */
displayFiles?: UploadFileItem[];
}
/**
* 自定义文件获取方式
*/
export interface FilePickerItem {
/**
* 方式编号
* @description 唯一标识,不可重复
*/
key: string;
/**
* 显示的名称
*/
name?: string | ((context: UploaderContext, customOptions: Record<string, any>) => string);
/**
* 文件获取的实现方法
* @description 当用户选择本方式后,将调用本方法来获取文件。
* 如果`handler`字段为空,且不存在默认配置,则用户选择此方式后将通过h5方式选取文件。
*/
handler?: (context: UploaderContext, customOptions: Record<string, any>) => Promise<FileItem[]>;
/**
* 是否显示
* @description 如果本方式仅部分平台支持,则应该根据平台的能力决定是否显示本方式
*/
visible?: boolean | ((context: UploaderContext, customOptions: Record<string, any>) => boolean);
/**
* 提示文本
* @description 显示在名称下方的一行文本
*/
tip?: string | ((context: UploaderContext, customOptions: Record<string, any>) => string);
/**
* 自定义选项
* @description 一般不需要配置
*/
customOptions?: Record<string, any>;
}
/** 文件条目的上下文数据 */
export interface FileItemContext {
/** 被选中的文件 */
file: UploadFileItem;
/** 被选中文件在文件列表中的下标 */
index: number;
/** 文件列表 */
fileList: UploadFileItem[];
/** 上传组件的上下文 */
uploaderContext: UploaderContext;
}
/**
* 文件条目的上下文菜单项
*/
export interface FileContextMenuItem {
/**
* 选项编号
* @description
* 唯一标识,不可重复。
* 1. 当`key='preview'`时,点击选项将触发预览,组件将执行默认的预览操作(可通过`preventDefaultPreview`禁用)并抛出预览事件;
* 2. 当`key='delete'`时,点击选项将触发删除,组件将向外抛出删除事件;
* 3. 当`key`等于其它值时,没有默认行为,需要用户通过`handler`方法自定义实现。
*/
key: 'preview' | 'delete' | string;
/**
* 显示的名称
*/
name?: string | ((context: FileItemContext, customOptions: Record<string, any>) => string);
/**
* 选项行为的实现方法
* @description 当用户选择本选项后,将调用本方法
*/
handler?: (context: FileItemContext, customOptions: Record<string, any>) => boolean;
/**
* 是否显示
* @description 默认显示,可以用来隐藏不被支持的选项
*/
visible?: boolean | ((context: FileItemContext, customOptions: Record<string, any>) => boolean);
/**
* 是否禁用
* @description 默认不禁用,当回调方法返回`true`或非空字符串时禁用,返回的字符串将被作为提示文本显示在名称下方,具有比`tip`更高的优先级
*/
disabled?:
| boolean
| ((context: FileItemContext, customOptions: Record<string, any>) => boolean | string);
/**
* 提示文本
* @description 显示在名称下方的一行文本
*/
tip?: string | ((context: FileItemContext, customOptions: Record<string, any>) => string);
/**
* 自定义选项
* @description 一般不需要配置
*/
customOptions?: Record<string, any>;
}
/**
* 弹层的类型
* @description 文件选取动作列表、文件条目上下文菜单的动作列表、文件条目上下文菜单的`tooltip`
*/
export enum UploaderPopupType {
FilePickerActionSheet = 'FilePickerActionSheet',
ContextMenuActionSheet = 'ContextMenuActionSheet',
ContextMenuTooltip = 'ContextMenuTooltip'
}
/**
* 上传文件列表变更上下文
*/
export interface FileListUpdateContext {
/**
* 变更来源
* @description
* 1. `add` 上传后新增文件
* 2. `delete` 点击删除按钮或者上下文菜单中的删除选项后删除文件
*/
trigger: 'add' | 'delete';
}
/** 文件上传前校验参数 */
export interface BeforeUploadValidationParam {
/** 待上传的(需要校验的)文件列表 */
files: FileItem[];
/** 已上传的文件列表 */
uploadedFiles?: UploadFileItem[];
/** 文件数量上限 */
maxCount?: number;
/** 单个文件的大小上限 */
maxSize?: number;
/** 是否允许重名文件 */
allowDuplicateFile?: boolean;
/** 单个文件上传前回调 */
beforeUpload?: (file: UploadFileItem, context: any) => boolean | Promise<boolean>;
/** 上下文 */
context?: any;
}
/** 文件条目长按事件默认行为 */
export enum FileItemLongPressAction {
/** 不进行默认处理 */
None = 'None',
/** 通过下方弹出的动作列表显示自定义的上下文菜单 */
ShowMenu = 'ShowMenu',
/** 通过`Tooltip`组件显示自定义的上下文菜单 */
ShowMenuInTooltip = 'ShowMenuInTooltip'
}
/** 校验发现问题的类型 */
export enum FileValidationProblemType {
SingleFileOverSizeLimit = 'SingleFileOverSizeLimit',
FileListOverLengthLimit = 'FileListOverLengthLimit',
DuplicateFileNames = 'DuplicateFileNames',
BeforeUploadCallback = 'BeforeUploadCallback'
}
/** 校验发现的问题 */
export interface FileValidationProblem {
/** 问题类型 */
type: FileValidationProblemType;
/**
* 相关的文件列表
* @description
* 1. 当`type="SingleFileOverSizeLimit"`时,是本次所选文件中所有超过单文件大小上限的文件;
* 2. 当`type="FileListOverLengthLimit"`时,是本次所选的所有文件;
* 3. 当`type="DuplicateFileNames"`时,是本次所选的文件中所有重名的文件;
* 4. 当`type="BeforeUploadCallback"`时,是本次所选的文件中所有未通过`beforeUpload`自定义校验的文件。
*/
files: UploadFileItem[];
}
/** 文件上传前校验结果 */
export interface BeforeUploadValidationResult {
/** 通过校验的文件列表 */
validFiles: UploadFileItem[];
/** 检测到的问题列表 */
problems?: FileValidationProblem[];
/**
* 校验参数
* @description 包含本次校验的上下文参数,禁止修改
*/
validationParam: BeforeUploadValidationParam;
}
属性
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| files | Array as UploadFileItem[] | [] | 已上传文件列表,支持语法糖v-model:files |
| readonly | boolean | false | 是否只读,只读状态下将隐藏上传按钮和删除按钮 |
| disabled | boolean | false | 是否禁用,禁用状态下将禁用上传按钮和删除按钮,优先级低于readonly属性 |
| listType | string as UploaderListType | 'details' | 文件列表的内建样式,支持两种基础样式:details(文件详情列表)、image-card(图片列表) |
| uploadButtonPosition | 'start' | 'end' | 'end' | 上传按钮的位置,默认在图片列表的右侧或文件详情列表的下方 |
| imageProps | Object | {} | 图片属性,透传给缩略图的图片相关属性 |
| fileReadType | string as FileReadType | 'file' | 文件读取的结果类型,指定用户所选文件是以File对象的形式返回,还是以 base64 格式的字符串的形式返回 |
| filePickerItems | Array as FilePickerItem[] | -- | 自定义的文件获取方式列表,如果为空,则用户点击上传按钮后通过 h5 选择文件,如果非空,则通过列表中定义的方式获取文件 |
| contextMenuItems | Array as FileContextMenuItem[] | [{ key: 'preview' }, { key: 'delete' }] | 自定义的上下文菜单。当listType='details'时,点击更多按钮,弹出上下文菜单。传入longPressAction属性,可以使得长按文件条目时弹出上下文菜单。 |
| preventDefaultPreview | boolean | false | 阻止默认的预览行为,默认情况下,如果点击了图片类型的文件条目,则进行预览,其它类型的文件没有默认的预览。可以将本属性置为true,然后通过文件条目点击事件或回调方法实现自定义的文件预览。 |
| getThumbnailUrl | (file: UploadFileItem) => string | Promise<string> | -- | 获取文件的预览图片地址,用户选择文件后,被选择的文件将被加入到文件列表中,此时文件的预览图地址可以根据本回调方法指定 |
| useOriginalImageAsThumbnail | boolean | true | 是否将原图作为缩略图,如果文件是图片类型,则直接将之作为缩略图显示出来,不再调用getThumbnailUrl方法 |
| accept | string | -- | 接受上传的文件类型,仅影响默认的文件获取方式,自定义的文件获取方式可以读取该属性,但是不一定受约束 |
| multiple | boolean | true | 是否启用文件多选,仅影响默认的文件获取方式,自定义的文件获取方式可以读取该属性,但是不一定受约束 |
| maxCount | number | -1 | 文件数量上限,值小于等于 0 则不限制 |
| maxSize | number | -1 | 单个文件的大小上限 (Bytes),值小于等于 0 则不限制 |
| allowDuplicateFile | boolean | true | 是否允许上传同名文件,如果值为false,则过滤掉被选择的重名文件 |
| beforeUpload | (file: UploadFileItem, context: UploaderContext) => boolean | Promise<boolean> | -- | 单文件上传前回调,如果返回false则将文件过滤掉 |
| onValidate | (result: BeforeUploadValidationResult) => boolean | Promise<boolean> | -- | 校验后回调,校验结果中包含通过校验的文件列表、校验时发现的问题列表,无论是否存在文件未通过校验都将触发该回调或事件。如果回调方法返回true则继续处理通过校验的文件,如果返回false则放弃所有文件。 |
| autoUpload | boolean | true | 是否在选择文件后自动上传,默认自动上传,如果手动上传,则文件被选中后处于等待状态,调用组件的上传方法后上传 |
| action | string | '' | 上传请求的地址,action非空且customUploadMethod为空时,启用内置的文件上传方式 |
| method | string as HttpMethod | 'POST' | HTTP 的请求方法,随action生效,可选值:POST/GET/PUT/OPTION/PATCH/post/get/put/option/patch |
| name | string | 'file' | 文件在上传请求数据中的字段名,随action生效,指定文件在请求数据中的字段名。如果fileReadType的值为file(默认)则文件作为File对象上传,如果fileReadType的值为dataUrl则文件作为 base64 格式的字符串上传。如果singleRequestUpload=true且用户选择了多个文件,所有文件将使用相同的字段名。如果默认的规则不能满足业务需求,请使用formatRequestData属性来自定义请求数据,或者通过customUploadMethod属性自定义上传方法。 |
| data | Object | -- | 上传请求所需的额外字段,随action生效,用于添加文件字段之外的其它字段。如果默认的规则不能满足业务需求,请使用formatRequestData属性来自定义请求数据。 |
| headers | Object | -- | 自定义 HTTP 请求头,随action生效 |
| withCredentials | boolean | false | 是否携带 cookie,随action生效,默认不携带 |
| timeout | number | -- | 上传请求的超时时间,随action生效,单位:毫秒,默认不设置 |
| formatRequestData | (files: UploadFileItem[], data: { [key: string]: any }) => { [key: string]: any } | -- | 自定义上传请求的参数,随action生效,用于自定义上传请求参数,本方法非空时,name和data字段均失效 |
| formatResponseData | (response: any, uploadFiles: UploadFileItem[]) => UploadResponseData | -- | 格式化上传请求的响应数据,随action生效,用于将上传请求返回的数据格式化为规定的结构。如果请求失败或者error字段非空,则认为文件上传失败。如果请求成功并且error字段为空,则认为文件上传成功。如果未设置本回调方法,则根据请求是否成功以及请求的原始响应数据中的error字段是否为空判断文件是否上传成功。如果singleRequestUpload=true单次请求上传多个文件,则所有上传的文件只能一起成功或者一起失败。如果既要单次请求上传多个文件,又要单独记录每个文件的上传成功和失败状态,请通过自定义上传方法customUploadMethod实现。 |
| customUploadMethod | (uploadContext: CustomUploadFileContext | CustomUploadFileContext[]) => void | -- | 自定义上传方法,如果非空,则使用本方法进行自定义上传,action等内置上传的相关字段均失效。本属性受singleRequestUpload字段影响:如果singleRequestUpload=true则用户选择多个文件时只会调用一次customUploadMethod,否则将调用多次。 |
| singleRequestUpload | boolean | false | 单次请求上传所有文件,如果有多个文件需要上传,若启用该属性则通过一个请求上传所有文件,否则每个文件发一次请求 |
| useMockProgress | boolean | true | 是否模拟上传进度 |
| onOneFileSuccess | (context: UploadResponseContext) => void | -- | 单文件上传成功回调方法,每个文件上传成功后都会调用该方法(singleRequestUpload=true时无效) |
| onOneFileFail | (context: UploadResponseContext) => void | -- | 单文件上传失败回调方法,每个文件上传失败后都会调用该方法(singleRequestUpload=true时无效) |
| onProgress | (context: UploadProgressContext) => void | -- | 上传进度变化回调方法,当文件的上传进度发生变化时回调该方法 |
| onUploadFinish | (result: UploadResult) => void | -- | 上传完成后回调方法,将用户单次选择的文件全部上传结束后回调 |
| onFileItemClick | (payload: { context: FileItemContext; event: MouseEvent }) => void | -- | 文件条目点击事件回调方法,当文件条目被点击时回调该方法,注意:点击文件条目上的删除按钮、菜单按钮不会回调该方法 |
| longPressAction | string as FileItemLongPressAction | 'None' | 文件条目长按事件默认行为,允许定制文件条目被长按后的具体行为 |
| longPressDelay | number | 600 | 触发文件条目长按事件默认行为所需要长按的最短时间,单位:ms,默认:600 |
| onLongPress | (payload: { context: FileItemContext; event: TouchEvent }) => void | -- | 文件条目长按事件回调方法,长按文件条目后回调本方法,与longPressAction属性的取值无关 |
| onDelete | (payload: { context: FileItemContext; event?: MouseEvent }) => void | -- | 删除回调方法,当用户点击文件条目上的删除按钮时回调该方法 |
| onPopupOpen | (payload: { close: () => void; type: UploaderPopupType; uid: string }) => void | -- | 打开弹层时回调方法,调用close方法可以主动关闭对应的弹层,且不会触发关闭弹层事件或回调。结合onPopupOpen和onPopupClose,可以实现对弹层的原生返回处理。 |
| onPopupClose | (payload: { type: UploaderPopupType; uid: string }) => void | -- | 关闭弹层时回调方法 |
事件
| 事件名 | 类型 | 说明 |
|---|---|---|
| validate | EventEmitter<BeforeUploadValidationResult> | 上传前校验事件 |
| progress | EventEmitter<UploadProgressContext> | 上传进度变化事件 |
| oneFileSuccess | EventEmitter<UploadResponseContext> | 单文件上传成功事件 |
| oneFileFail | EventEmitter<UploadResponseContext> | 单文件上传失败事件 |
| uploadFinish | EventEmitter<UploadResult> | 上传完成后事件 |
| fileItemClick | EventEmitter<{ context: FileItemContext; event: MouseEvent }> | 文件条目点击事件 |
| delete | EventEmitter<{ context: FileItemContext; event?: MouseEvent }> | 文件条目删除事件 |
| longPress | EventEmitter<{ context: FileItemContext; event: TouchEvent }> | 文件条目长按事件 |
| popupOpen | EventEmitter<{ close: () => void; type: UploaderPopupType; uid: string }> | 打开弹层事件 |
| popupClose | EventEmitter<{ type: UploaderPopupType; uid: string }> | 关闭弹层事件 |
插槽
| 名称 | 说明 |
|---|---|
| uploadButtonContent | 上传按钮内容 |
| uploadButton | 上传按钮,优先级高于uploadButtonContent |
| default | 上传按钮,同uploadButton |
组件实例
| 名称 | 类型 | 说明 |
|---|---|---|
| displayFiles | Ref<UploadFileItem[]> | 显示的文件列表 |
| toUploadFiles | Ref<UploadFileItem[]> | 待上传的文件列表 |
| uploading | Readonly<Ref<boolean>> | 是否正在上传 |
| uploaderContext | UploaderContext | 组件上下文 |
| triggerUpload | () => void | 触发上传操作,选择文件并上传 |
| uploadFiles | (files?: UploadFileItem[]) => void | 上传文件,手动上传模式下,可以通过调用本方法将准备上传状态的文件上传 |
CSS 变量
| 名称 | 默认值 | 说明 |
|---|---|---|
| --fm-uploader-gap | 12px | -- |
| --fm-uploader-gap-horizontal | var(--fm-uploader-gap) | -- |
| --fm-uploader-gap-vertical | var(--fm-uploader-gap) | -- |
| --fm-uploader-item-box-shadow | unset | -- |
| --fm-uploader-image-card-item-background | #f2f2f2 | -- |
| --fm-uploader-image-card-mask-background | rgba(0, 0, 0, 0.4) | -- |
| --fm-uploader-thumbnail-width | unset | -- |
| --fm-uploader-thumbnail-height | unset | -- |
| --fm-uploader-thumbnail-border-radius | 6px | -- |
| --fm-uploader-add-btn-size | unset | -- |
| --fm-uploader-add-btn-width | var(--fm-uploader-add-btn-size) | -- |
| --fm-uploader-add-btn-height | var(--fm-uploader-add-btn-size) | -- |
| --fm-uploader-add-btn-background | unset | -- |
| --fm-uploader-add-btn-border-radius | unset | -- |
| --fm-uploader-add-btn-box-shadow | unset | -- |
| --fm-uploader-add-btn-icon-size | unset | -- |
| --fm-uploader-add-btn-icon-color | #929292 | -- |
| --fm-uploader-del-btn-size | 16px | -- |
| --fm-uploader-del-btn-background | #666666 | -- |

