ant-design-vue Upload 组件完全指南:API 详解、拖拽上传与源码实现剖析
2026/9/20 2:29:49 网站建设 项目流程

ant-design-vue Upload 组件完全指南:API 详解、拖拽上传与源码实现剖析

【免费下载链接】ant-design-vue🌈 An enterprise-class UI components based on Ant Design and Vue. 🐜项目地址: https://gitcode.com/gh_mirrors/an/ant-design-vue

本文以 ant-design-vue 官方文档 components/upload/index.en-US.md 为核心骨架,系统讲解 Upload 组件的全部 API、事件模型、UploadFile 数据结构与 FAQ 高频问题,并结合仓库源码(Upload.tsx、interface.tsx、utils.tsx)与 17 个官方 Demo 进行源码级佐证。读完本文,你将掌握点击上传、拖拽上传、照片墙、手动上传、数量限制等完整实战方案,并能理解beforeUpload拦截、change事件触发机制、缩略图生成等底层实现原理。

Upload(上传)是表单类(Data Entry)组件中发布信息(网页、文本、图片、视频等)到远程服务器的核心入口。ant-design-vue 的 Upload 组件由点击上传的AUpload与拖拽上传的AUploadDragger(即<a-upload-dragger>)两个组件构成,二者在 index.tsx 中被统一导出并注册为全局组件,同时还导出了LIST_IGNORE常量与UploadDragger别名。

一、何时使用 Upload

上传是将信息(网页、文本、图片、视频等)通过网页或上传工具发布到远程服务器的过程。当出现以下需求时,应使用 Upload 组件:

  • 需要上传一个或多个文件;
  • 需要展示上传进度过程;
  • 需要支持拖拽文件到上传区域。

从 Upload.tsx 的组件定义可见,Upload 的默认配置为:type: 'select'(点击选择模式)、multiple: falseaction: ''data: {}accept: ''showUploadList: truelistType: 'text'supportServerRender: true

二、API 全量详解

以下表格完整继承自官方文档,并结合 interface.tsx 中的uploadProps()定义补充了底层类型约束说明。API 版本标记如3.0表示自 ant-design-vue 3.0 起可用。

Property说明类型默认值版本
accept接受上传的文件类型,对应原生<input accept>属性string-
action上传的 URL,可以是字符串,也可以是返回字符串或 Promise 的函数string | (file) =>Promise-
beforeUpload上传前执行的钩子函数,返回false或 rejected Promise 将停止上传(file, fileList) =>boolean|Promise-
customRequest覆盖默认 xhr 行为,用于自定义上传请求实现function-
data上传所需参数,可为对象或返回参数对象的函数object | function(file)-
directory支持上传整个目录(浏览器需支持 input-file-directory)booleanfalse3.0
disabled禁用上传按钮boolean-
downloadIcon自定义下载图标v-slot:iconRender="{file: UploadFile}"-3.0
fileList已上传的文件列表(受控)object[]-
headers设置请求头,IE10 以上生效object-
iconRender自定义显示图标v-slot:iconRender="{file: UploadFile, listType?: UploadListType}"-3.0
isImageUrl自定义判断是否在缩略图中渲染<img />(file: UploadFile) => boolean-3.0
itemRender自定义上传列表项v-slot:itemRender="{originNode: VNode, file: UploadFile, fileList: object[], actions: { download, preview, remove }"-3.0
listType内置样式,支持textpicturepicture-card三种stringtext
maxCount限制上传文件数量,为1时用新文件替换当前文件number-3.0
method上传请求的 HTTP 方法stringpost1.5.0
multiple是否支持多选文件(IE10+ 支持,按住 CTRL 可多选)booleanfalse
name上传文件的字段名stringfile
openFileDialogOnClick点击时打开文件对话框booleantrue3.0
previewFile自定义预览文件逻辑(file: File | Blob) => Promise<dataURL: string>-1.5.0
previewIcon自定义预览图标v-slot:iconRender="{file: UploadFile}"-3.0
progress自定义进度条,支持 ProgressProps(仅type="line"object{ strokeWidth: 2, showInfo: false }3.0
removeIcon自定义删除图标v-slot:iconRender="{file: UploadFile}"-3.0
showUploadList是否显示默认上传列表,可为对象以单独控制showPreviewIconshowRemoveIconshowDownloadIconboolean | { showPreviewIcon?, showRemoveIcon?, showDownloadIcon? }trueshowDownloadIcon(3.0)
supportServerRender服务端渲染时需要开启booleanfalse
withCredentialsajax 上传携带 cookiebooleanfalse

2.1 源码中的类型约束(锦上添花)

在 interface.tsx 中,uploadProps()定义了所有属性的 Vue 组件 prop 声明,以下几点值得关注:

  • actiondata均通过someType支持多类型:action可以是string | ((file) => string) | ((file) => PromiseLike<string>)data可以是Record<string, unknown> | ((file) => Promise<Record<string, unknown>>)
  • method被限定为'POST' | 'PUT' | 'PATCH' | 'post' | 'put' | 'patch'
  • capture支持boolean | 'user' | 'environment',用于移动端相机调用,这正是 FAQ 中"移动端选择相册或文件夹"问题的答案所在。
  • transformFileremove属性已被标记为@deprecated,官方建议分别改用beforeUploadonRemove事件。Upload 组件在挂载时(Upload.tsx)会通过devWarning对已废弃用法给出控制台警告。
  • progress的类型为UploadListProgressProps,即Omit<ProgressProps, 'percent' | 'type'>,这与文档中"仅支持type="line""的说明一致。

另外,fileList支持v-model:file-list双向绑定:在 Upload.tsx 中通过useMergedState合并受控的fileList与默认的defaultFileList,并会自动为缺少uid的文件生成__AUTO__${timestamp}_${index}__形式的唯一标识;onInternalChange中还会调用props['onUpdate:fileList']以支持 v-model 语法。

三、事件(events)

事件名说明参数版本
change上传状态变化时的回调function-
download点击下载文件的方法,传入方法则执行自定义逻辑,不传则默认跳转新 TABfunction(file): void1.5.0
drop文件被拖拽到上传区域时执行的回调(event: DragEvent) => void3.0
preview点击文件链接或预览图标时执行的回调function(file)-
reject拖入不符合 accept 的文件时执行的回调function(fileList)-
remove点击删除文件按钮时执行,返回 false 或 resolve(false)/reject 的 Promise 时阻止删除function(file): boolean | Promise3.0

3.1 事件源码行为说明

  • change:在 Upload.tsx 的onInternalChange中实现。其内部会先根据maxCount裁剪文件列表(maxCount === 1slice(-1)只保留最新文件,否则slice(0, maxCount)截取前 N 个),再组装{ file, fileList, event? }参数向外派发。
  • remove 的可取消机制handleRemove(Upload.tsx)会通过Promise.resolve包装onRemove的返回值,若结果为false则直接返回阻止删除;删除成功后会将文件status置为removed、调用底层upload.value?.abort(currentFile)中止正在进行的请求,并触发change
  • droponFileDrop(Upload.tsx)会同步维护dragStatedrop/dragover/dragleave),并在e.type === 'drop'时调用props.onDrop?.(e)。拖拽状态会反映到样式类上:ant-upload-drag-hoverant-upload-drag-uploading等(见 Upload.tsx)。
  • download 默认行为:在 UploadList/index.tsx 的onInternalDownload中,若未传入onDownload且文件存在url,则默认执行window.open(file.url)新开 TAB。

四、UploadFile 数据结构

UploadFile扩展自原生File,并附加以下属性(完整定义见 interface.tsx):

Property说明类型默认值版本
crossOriginCORS 设置属性'anonymous'|'use-credentials'|''-3.3.0
name文件名string-
percent上传进度百分比number-
status上传状态,配置后显示不同样式error|success|done|uploading|removed-
thumbUrl缩略图 URLstring-
uid唯一标识,未提供时自动生成string-
url下载 URLstring-

此外,源码中UploadFile还包含sizelastModifiedlastModifiedDateoriginFileObj(原始文件对象)、response(服务端响应)、errorlinkPropstypexhrpreview等字段。其中originFileObj在兼容场景下用于追溯原始文件,InternalUploadFile则强制要求携带originFileObj

4.1 文件对象的内部转换

当用户选择文件后,utils.tsx 中的file2Obj会将原生File转换为InternalUploadFile:复制lastModifiedlastModifiedDatenamesizetypeuid等字段,初始化percent: 0,并保留originFileObj指向原始文件。列表的增改删分别由updateFileList(按 uid 替换或追加)、getFileItemremoveFileItem(按 uid 或 name 匹配)完成。

五、change 回调详解

change 函数会在上传进行中、完成或失败时被调用。

当上传状态变化时,change 回调返回如下结构:

{ file: { /* ... */ }, fileList: [ /* ... */ ], event: { /* ... */ }, }
  1. file:当前操作的文件对象。

    { uid: 'uid', // 唯一标识,推荐使用负数,避免与内部生成的 id 冲突 name: 'xx.png', // 文件名 status: 'done', // 可选值:uploading, done, error, removed response: '{"status": "success"}', // 服务端响应 linkProps: '{"download": "image"}', // 文件链接的附加 html 属性 xhr: 'XMLHttpRequest{ ... }', // XMLHttpRequest 头信息 }
  2. fileList:当前的文件列表。

  3. event:服务端响应,包含上传进度,高级浏览器支持。

在 Upload.tsx 中,上传成功、进度、失败分别由onSuccessonProgressonError处理:成功时解析 JSON 响应、将状态置为donepercent置为100,并记录responsexhr;进度更新时将percent写入event;失败时记录errorresponse、状态置为error。三者都会先通过getFileItem校验文件是否仍在列表中(已被移除则忽略事件),再以updateFileList生成新列表并触发onInternalChange

一个典型的 change 使用方式(来自官方 Demo demo/basic.vue):

const handleChange = (info: UploadChangeParam) => { if (info.file.status !== 'uploading') { console.log(info.file, info.fileList); } if (info.file.status === 'done') { message.success(`${info.file.name} file uploaded successfully`); } else if (info.file.status === 'error') { message.error(`${info.file.name} file upload failed.`); } };

六、三种内置列表样式(listType)

listType支持三种取值,源码类型定义为'text' | 'picture' | 'picture-card'(见 interface.tsx):

  • text:默认样式,仅显示文件名、状态与操作图标;
  • picture:图片列表样式,显示缩略图;
  • picture-card:照片墙卡片样式,上传按钮内嵌于列表末尾。

在 UploadList/index.tsx 中有一个关键实现细节:当listTypepicturepicture-card时,组件会通过watchEffect遍历文件列表,对拥有originFileObjFileBlob实例)且尚无thumbUrl的文件,调用默认的previewFile(即 utils.tsx 中的previewImage)异步生成缩略图并回填thumbUrlpreviewImage内部使用 200×200 的 canvas 等比缩放绘制图片,并将非图片文件解析为空字符串。

照片墙的典型用法见 demo/picture-card.vue:通过list-type="picture-card"展示缩略图,配合@preview事件与a-modal实现点击放大预览,并通过v-if="fileList.length < 8"控制"上传按钮在达到数量上限后消失"。

七、拖拽上传(Upload.Dragger)

拖拽上传由<a-upload-dragger>实现。其源码 Dragger.tsx 非常简洁:将type强制置为'drag',并把height属性转换为行内style.height(数字自动加px)后透传给AUpload

在 Upload.tsx 中,type === 'drag'时会渲染带拖拽区域的包裹结构,并通过onDroponDragoveronDragleave三个事件维护dragState,最终生成ant-upload-dragant-upload-drag-uploadingant-upload-drag-hoverant-upload-disabled等样式类。

官方示例 demo/drag.vue:

<a-upload-dragger v-model:file-list="fileList" name="file" :multiple="true" action="https://www.mocky.io/v2/5cc8019d300000980a055e76" @change="handleChange" @drop="handleDrop" > <p class="ant-upload-drag-icon"> <inbox-outlined></inbox-outlined> </p> <p class="ant-upload-text">Click or drag file to this area to upload</p> <p class="ant-upload-hint"> Support for a single or bulk upload. Strictly prohibit from uploading company data or other band files </p> </a-upload-dragger>

设置multiple后,可一次拖入多个文件同时上传。

八、受控列表与限制数量(fileList / maxCount)

  • fileList(受控):通过v-model:file-list="fileList"或单向绑定:file-list控制上传列表。官方文档特别提醒,受控 fileList 存在一个常见问题(见 issue #2423):change只在文件仍在列表中时触发,文件被移出列表后会忽略其后续事件。同时需注意在3.0.0-beta.10之前存在一个 bug,会导致文件不在列表中时事件依然触发。
  • maxCount(数量限制):当maxCount1时,始终用最新上传的文件替换当前文件;大于1时截取列表前 N 个。其实现位于 Upload.tsx:maxCount === 1cloneList.slice(-1),否则cloneList.slice(0, maxCount)。官方示例 demo/max-count.vue 分别演示了:max-count="1":max-count="3"的效果。

九、手动上传(beforeUpload 返回 false)

当需要自行控制上传时机(如用户点击"开始上传"按钮后再提交)时,可让beforeUpload返回false拦截自动上传。其底层逻辑在 Upload.tsx 的mergedBeforeUpload中:

  • beforeUpload返回false,直接终止上传流程(文件仅加入列表,不发起请求);
  • 若返回LIST_IGNORE常量(Upload.tsx 中定义为`__LIST_IGNORE_${Date.now()}__`),则文件连列表都不加入;
  • 若返回对象,则作为替换后的文件继续上传。

官方示例 demo/upload-manually.vue 的完整流程:

const beforeUpload: UploadProps['beforeUpload'] = file => { fileList.value = [...(fileList.value || []), file]; return false; // 阻止自动上传 }; const handleUpload = () => { const formData = new FormData(); fileList.value.forEach(file => { formData.append('files[]', file as any); }); uploading.value = true; // 使用任意 AJAX 库发起上传 request('https://www.mocky.io/v2/5cc8019d300000980a055e76', { method: 'post', data: formData, }) .then(() => { /* 清空列表、提示成功 */ }) .catch(() => { /* 提示失败 */ }); };

十、自定义请求(customRequest)

customRequest用于覆盖默认的 XMLHttpRequest 上传行为,实现自定义的上传请求(如使用分片上传、第三方 SDK、WebSocket 等)。其类型为(options: RcCustomRequestOptions) => void(见 interface.tsx),RcCustomRequestOptions源自底层的vc-upload组件。官方文档建议参考 react-component/upload 的 customRequest 用法说明,该方案同样适用于 ant-design-vue。

十一、自定义图标与列表渲染(iconRender / itemRender)

  • iconRender / removeIcon / previewIcon / downloadIcon:均可通过作用域插槽自定义。在 UploadList/index.tsx 的internalIconRender中,默认逻辑为:上传中显示LoadingOutlinedtext列表显示PaperClipOutlinedpicture/picture-card列表根据isImageUrl判断显示PictureTwoTone(图片)或FileTwoTone(文件),picture-card上传中则显示本地化的"上传中"文案。
  • itemRender:完全自定义上传列表项,接收{ originNode, file, fileList, actions: { download, preview, remove } },其中actions可直接触发对应操作。
  • showUploadList 细分控制:传对象{ showPreviewIcon, showRemoveIcon, showDownloadIcon }可分别控制预览、删除、下载图标的显隐。注意默认showDownloadIconfalse(见 UploadList/index.tsx),需显式开启。

十二、FAQ 高频问题

12.1 如何实现服务端上传接口?

  • 可参考 jQuery-File-Upload 关于服务端上传接口的说明。
  • rc-upload 中提供了一个基于 express 的 mock 示例可供参考。

12.2 移动端如何选择相册或文件夹?

设置:capture="null"即可。

12.3 想显示下载链接怎么办?

fileList中每一项设置url属性即可控制链接内容。

12.4 如何使用 customRequest?

参考 react-component/upload 的 customRequest 文档。

12.5 受控 fileList 中文件不在列表时为何不触发 change 的 status 更新?

change只在文件位于列表内时触发,文件被移出列表后会忽略其后续事件。注意:在3.0.0-beta.10之前存在 bug,即使文件不在列表中事件仍会触发。

12.6 为什么 change 有时返回 File 对象,有时返回 { originFileObj: File }?

这是兼容性处理:当beforeUpload返回false时返回 File 对象;下一主版本将合并为{ originFileObj: File }。当前版本可通过info.file.originFileObj获取原始文件。从源码看,Upload.tsx 在beforeUpload返回false时,会尝试用new File([originFileObj], originFileObj.name, { type })构造克隆对象(不支持 File 的环境回退到 Blob 并补齐 name、lastModified 等字段),以保证 change 回调中的 file 形态兼容。

12.7 为什么 Chrome 偶尔无法上传?

Chrome 更新可能破坏原生上传功能,重启 Chrome 即可恢复。相关参考 issue:

  • #32672
  • #32913
  • #33988

十三、进阶:与 Form 表单集成的细节

Upload 与 Form 组件深度集成。在 Upload.tsx 中通过useInjectFormItemContext()获取表单项上下文,将id回填到上传按钮(props.id ?? formItemContext.id.value),从而支持点击 label 聚焦;同时在onInternalChange中调用formItemContext.onFieldChange()通知表单校验更新(Upload.tsx)。当没有默认插槽内容或组件被禁用时,会删除id以避免点击 label 误触发文件对话框(Upload.tsx)。

十四、更多官方 Demo 一览

components/upload/demo/目录下共提供 17 个可直接运行的示例,除本文已引用的外,还包括:

  • avatar.vue:上传头像;
  • directory.vue:整目录上传;
  • defaultFileList.vue:默认文件列表(非受控);
  • fileList.vue:受控列表;
  • custom-render.vue:itemRender 自定义列表项;
  • customize-progress-bar.vue:自定义进度条;
  • preview-file.vue:自定义预览逻辑;
  • transform-file.vue:文件转换(演示已废弃的 transformFile,新项目应使用 beforeUpload);
  • upload-png-only.vue:仅接受 png 类型;
  • upload-custom-action-icon.vue:自定义操作图标。

结语

ant-design-vue 的 Upload 组件以"选择上传 + 拖拽上传"双形态覆盖了绝大多数文件上传场景,配合beforeUpload拦截、customRequest自定义请求、maxCount数量限制、三种listType样式与丰富的插槽定制能力,可灵活适配从简单的单文件上传到复杂的照片墙、手动批量上传等业务需求。理解其背后mergedBeforeUploadonInternalChangefile2Obj等源码实现,将帮助你在遇到受控列表、事件触发时机、兼容性等疑难问题时快速定位根因。

【免费下载链接】ant-design-vue🌈 An enterprise-class UI components based on Ant Design and Vue. 🐜项目地址: https://gitcode.com/gh_mirrors/an/ant-design-vue

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询