前言
文件上传是我们开发中不可或缺的一部分,我们将在本文深入解析Ant Design Upload
组件的实现。
相信看完以后对于React
以及Ant Design
的工作原理理解能更上一层楼。
Upload.tsx
入口函数upload.tsx
直接引用了AjaxUpload
组件,引用了一些能力,并把ant-design
的props
给传了进去,如图:
我们去这个组件看核心逻辑
AjaxUpload.tsx
组件一共分了这些事件函数:
我们来依次拆解这些事件干了啥。
onChange
:input onchange,上传文件逻辑;onClick
:点击事件,点击调起选择文件弹窗逻辑;onKeyDown
:同onClick
事件;onFileDrop
:文件拖拽事件,监测文件拖拽到上传区,上传文件;componentDidMount
:组件挂载,标志isMounted
;componentWillUnMount
:组件即将销毁,标志isMounted
;uploadFiles
:上传文件,调用请求函数;processFile
:文件即将上传的业务逻辑,获取action
上传地址、调用beforeUpload
、格式化文件对象结构;post
:上传请求事件;reset
:重置状态;abort
:文件上传中断请求;saveFileInput
:挂载input元素ref;render
:渲染DOM;
文件上传流程大概是这样的:触发input
的原生事件->触发uploadFiles
->触发post
请求。
我们先看input
原生事件。
所有事件触发都在这里,挂载在了input元素上,以onChange
事件为例,我们看下它的实现:
实现方案也比较易懂,就是原生js的解析文件,这里有directory
的props。
- 如果支持文件夹,则调用
attrAccept
把文件夹中的文件遍历出来; - 如果不支持,则取选中的文件,如果没有文件则不上传;
然后就走到了uploadFiles
函数了。
这里会有两部分,上半部分会调用processFile
函数,结构化原生的File
对象,转换成RcFile
的类型,并且在这个函数中去执行beforeUpload
的回调函数。
下半部分会基于结构化完的文件数组,分批去调用post
上传文件。
processFile
函数的返回就像这样:
然后还进行了一些props
传入的参数处理,包括事件回调、请求地址解析等等。
然后就到了请求的逻辑部分,我们看下post
函数。
逻辑比较清晰,主要做了几件事情。
- 判断组件是否挂载,还没挂载则不请求;
- 读取
antd props
传过来的上传中的事件以及请求的数据,事件有onStart
、onProgress
、onSuccess
、onError
,请求数据包含name
、headers
、withCredentials
、method
,以及可以选择业务侧自己实现的请求request
方法; - 调用
request
,发送请求;
那我们看下defaultRequest
的请求实现,走到request.ts
文件里去。
request.ts
request
函数中创建了一个XMLHttpRequest
对象。
并在函数最后暴露出了一个abort
中断请求函数:
而函数主体做了这些事情:
-
上传请求的配置:
UploadRequestOption
作为参数,定义了上传请求的相关选项,如请求的方法、目标 URL、要上传的文件、附加数据、请求头等。
-
错误处理:
getError
函数用于生成一个自定义的错误对象,包括请求方法、URL 和 HTTP 状态码。此函数在发生请求错误时被调用。
-
响应体处理:
getBody
函数用来处理服务器返回的响应,尝试将响应文本解析为 JSON,如果解析失败,则返回原始文本。
-
进度监控:
- 使用
xhr.upload.onprogress
来监控文件上传的进度,并在option.onProgress
中回调进度事件。
- 使用
-
FormData 的组装:
- 根据提供的
option.data
和option.file
,创建一个FormData
对象,将所有需要上传的数据(包括文件)添加到这个对象中。
- 根据提供的
-
请求的发送:
- 配置请求头,并设置是否需要带上凭证(例如,cookies)。最后,通过
xhr.send(formData)
发送请求。
- 配置请求头,并设置是否需要带上凭证(例如,cookies)。最后,通过
-
事件处理:
- 处理请求的错误事件和加载完成事件。在成功响应的时候,判断状态码是否在 2xx 范围内,并分别调用
onError
或onSuccess
处理成功与失败的情况。
- 处理请求的错误事件和加载完成事件。在成功响应的时候,判断状态码是否在 2xx 范围内,并分别调用
-
请求的中止:
- 返回一个对象,其中包含一个
abort
方法,用于在需要的时候可以中止当前的请求。
- 返回一个对象,其中包含一个
在一开始,为函数绑定了xhr
对应的事件,以及请求体的数据。
基于ajax
的请求准备工作做完,最后将请求发送了出去,就像这样:
实现还是比较轻巧的,再回到组件中。其实事情也都做完了,在上传过程中,业务侧能通过组件的所有事件来获取到上传的数据。
我们上面主要基于onChange
事件开启上传的整个链路的分析,再看下其他函数呢?其实本质上是一样的。
先看onClick
事件。
直接获取到了input
元素的DOM,然后基于ref
的形式触发了点击事件,接下来选择完文件走的还是onChange
的逻辑,并且调用了props.onClick
的回调。
再看下onKeyDown
事件,也只是在回车后调用了onClick
。
最后再看下onFileDrop
拖拽事件,也是基于是否支持文件夹、是否支持多选,来进行原生File
对象的解析和组装,最后调用uploadFiles
。
到这里,ant-design
的底层上传组件能力已经讲完了,是否感觉没有想象中那么复杂呢?
结尾
如果你有任何问题,欢迎在评论区留言讨论。
本专栏会定期更新,最后讲解完所有组件,欢迎关注。
源码地址:
https://github.com/react-component/upload/tree/master
如果喜欢我的文章或者想上岸大厂,可以关注公众号「量子前端」[1],将不定期关注推送前端好文、分享就业资料秘籍,也希望有机会一对一帮助你实现梦想。