代码
- 页面展示代码
<Modal
visible={
isShowUploadModal} //弹框是否显示
onOk={
this.handleCloseModel} // 点击确定时的操作
onCancel={
this.handleCloseModel} //点击取消时的操作
title="文件上传"
// 关闭时销毁子元素,这个很有用,相当于关闭的时候结束了组件的生命周期
destroyOnClose={
true}
>
<Upload
ref={
this.modalRef} // 用到ref实现后面的弹框颜色控制
action={
apis.DeviceManagement} // 上传的地址
headers={
{
Authorization: token } // 可以在header里加上token
}
maxCount={
1} // 最大上传数量,控制为1
accept=".xls, .xlsx" //upload文件接收什么样的文件
beforeUpload={
this.handlerBeforeUpload} // 上传前的操作记录
onChange={
this.statusChange} //上传后的操作记录
>
<Button type="primary">
点击上传
</Button>
</Upload>
</Modal>
- 事件处理代码
// 文件上传的拦截
handlerBeforeUpload = (file, fileList) => {
const {
size } = file
if (size / 1024 / 1024 > 10) {
message.error("文件大小不能超过10兆")
return Upload.LIST_IGNORE
}
this.setState({
uploadLoading: true
})
return true
}
//onChange上传文件状态变化,有三个状态status:uploading done error。
//beforeUpload拦截的文件没有这些status
// 所以在onChange中将拦截的文件进行处理,一般来说,上传的文件要么走到error,
//要么走到done,进入error状态,代表接口报错了。走到done状态代表了上传成功状态。
statusChange = (res) => {
const {
file, fileList } = res
if (file.status == 'error') {
message.error(file?.response?.msg||"文件上传失败,请检查一下数据是否有错")
}
if (file.status == 'done') {
// 上传成功后重新获取数据
if (file.response.code === 100) {
// 通过ref将upload组件获取到后,调用上传失败的函数,实现在已经done后还能触
//发向error状态时的字体颜色为红色状态
this.modalRef.current.onError("文件上传失败", file.response, file)
}
if (file.response.code === 200) {
message.success(file.response?.msg || "文件上传成功")
// 上传成功后重新获取数据
// this.getDeviceList()
}
}
}
问题
- 知识点
onChange上传文件状态变化,有三个status:uploading, done ,error。
beforeUpload拦截的文件是没有这些status的,所以在onChange中将拦截的文件进行处理,一般来说,上传的文件要么走到error,要么走到done,进入error状态,代表接口报错了。走到done状态代表了上传成功状态。 - 问题
因为上传的是excel文件,用后端对接接口返回的状态码来判断是否上传成功,还有显示后端的提示代码。所以这个时候已经走到done了,能拿到了状态和后端返回的response。但是后面遇到的问题是要在done这个状态里面判断是否上传成功,没有成功就让上传的文件变为红色,类似于下图
想到的解决办法就是 - 1,要么利用变量控制css属性来实现
实现起来有些问题,虽然可以通过浏览器元素审查来找到upload对应的类名进行修改。但是这样写的话可能就会通过操作dom元素来实现style的添加或删除颜色,与react的虚拟dom设计不符合,所以放弃 - 2,通过upload自己来触发让他变红的事件(onError)
react的ref属性可以获取到想要获取的元素。通过ref拿到后upload的属性后进行Onerror的调用this.modalRef.current.onError("文件上传失败", file.response, file)
,file.response
就是后台返回的数据,file
是上传的文件。
遇到的坑
- 场景
因为upload嵌套在modal弹框里面,所以在点击弹框关闭时要将upload里面上传的文件销毁,或者说是清空upload中的fileList - 问题
将fileList变为受控组件后,onChange事件拿到的状态一直是uploading
<Upload
ref={
this.modalRef}
action={
apis.DeviceManagement}
headers={
{
Authorization: Token.token }
}
fileList={
fileList} // 将fileList变为受控组件
maxCount={
1}
accept=".xls, .xlsx"
beforeUpload={
this.handlerBeforeUpload}
onChange={
this.statusChange}
>
</Upload>
查阅了一下antd官网
为何 fileList 受控时,上传不在列表中的文件不会触发 onChange 后续的 status 更新 事件?
onChange 事件仅会作用于在列表中的文件,因而 fileList 不存在对应文件时后续事件 会被忽略
- 解决方案
最简方案,那么就在fileList不写在upload中,还是非受控的。modal关闭时销毁其子组件,刚好modal进行过封装destroyOnClose
={true},当弹框关闭时可以销毁组件。
destroyOnClose关闭时销毁 Modal 里的子元素