背景
许多ToB项目的业务中都有表单提交的需求,AntDesgin的Upload上传组件,封装的功能非常全面。下面我结合实际项目需求完整介绍如何使用Upload组件。
上传是将信息(网页、文字、图片、视频等)通过网页或者上传工具发布到远程服务器上的过程。
复制代码
功能清单
- 项目使用的技术栈:React + Hooks + AntDesgin
- 项目实际对上传功能的需求点:
- 文件上传需要进行校验【重复性校验、文件数量限制、文件大小限制、文件格式限制等】
- 文件下载的名称保持和文件上传名称相同,并且支持自定义名称
- 已上传列表可以进行文件预览、文件下载功能
实际代码
首先需要在页面中引入相关的依赖,然后在render中编写具体的组件和页面布局。
import React, { useEffect, useState } from 'react';
import { UploadOutlined } from '@ant-design/icons';
import { Button, Upload, message } from 'antd';
const FromComponent = (props)=>{
return <Upload>
<Button icon={<UploadOutlined/>}>上传文件</Button>
<p style={{color:"gray"}}>支持扩展名: .doc .docx .pdf .jpg .png </p>
</Upload>
}
复制代码
上面的代码示例只会呈现默认的上传效果和功能,无法实现诸如限制文件、预览文件、下载文件
等功能。需要加入配置选项并使用AntDesgin提供的各类Api方法中找到需要的进行配置
文件上传前的处理 – beforeUpload(file) 钩子函数
- 重复性校验
- 文件数量限制
- 文件大小限制
- 文件格式限制
// 上传文件之前的钩子 - 其中fileDateList是已上传的文件列表数据
beforeUpload: file => {
var sameList = fileDateList.filter(item => item.lastModified == file.lastModified);
if (sameList.length >= 1) {
message.error(`请勿重复上传同一文件`);
return Upload.LIST_IGNORE;
} else if (fileDateList.length == 10) {
message.error(`文件数量最多上传10个`);
} else if (file.size > 10240000) {
message.error(`文件过大,请重新选择10M以内的文件`);
return Upload.LIST_IGNORE;
} else if(!['image/png','image/jpeg','application/pdf','application/msword']
.includes(file.type)) {
message.error(`文件格式错误`);
return Upload.LIST_IGNORE;
} else if(file.name.length > 50) {
message.error(`请选择名称在50字符以内的文件`);
return Upload.LIST_IGNORE;
} else {
return true;
}
},
复制代码
上传文件改变时的状态 – onChange(info)
- info 包含info.file 和 info.fileList
- info.file.status 状态包含 error | success | done | uploading | removed
- info.file.response 表示文件上传后端的返回信息(根据自己项目后端接口定义)
- fileList 是根据自己项目表单提交所需要的数据格式定义的一个文件上传数组
- 重组fileDateList 是因为在实现预览功能时组件会默认检测file是否拥有url属性
onChange(info) {
if (info.file.status === 'done') { // 新增文件
setFileList([...fileList,{
fileName: info.file.name,
fileUrl: info.file.response.data,
}]);
if (info.file.response.returnCode == '17000') {
message.success('文件上传成功');
} else {
message.error('文件上传失败');
}
} else if (info.file.status === 'removed') { // 删除文件
const index = fileList.findIndex(item =>
item.name === info.file.name);
fileList.splice(index, 1);
setFileList(fileList);
}
let list = [...info.fileList]; // 重组fileDateList
list = list.map(file => {
if (file.response) {
file.url = file.response.data;
}
return file;
});
setFileDateList([...list]);
},
复制代码
点击预览文件的钩子函数 – onPreview(file)
添加onPreview会将组件默认的预览行为覆盖,这里进行覆盖的原因是,文件格式为doc的下载后要对文件名称自定义,并且区分文件类型来分流(预览 or 下载)
onPreview(file){ // 文件预览
if (['image/png','image/jpeg','application/pdf'].includes(file.type)) {
var link = document.createElement('a');
link.target = '_black';
link.href = file.url;
link.click();
} else {
bizFuns.downLoadFile({
item:{
fileName: file.name,
fileUrl: file.url,
}
})
}
}
复制代码
downLoadFile方法实现如下:
// 下载文件
downLoadFile(file) {
var fileName = file.item.fileName;
var fileUrl = file.item.fileUrl;
getBlob(fileUrl).then(blob => {
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = fileName;
link.click();
});
}
// 文件下载拿到blob对象
getBlob(url){
return new Promise(resolve => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onload = () => {
if (xhr.status === 200) {
resolve(xhr.response);
}
};
xhr.send();
})
},
复制代码
完整配置示例代码奉上:
import React, { useEffect, useState } from 'react';
import { UploadOutlined } from '@ant-design/icons';
import { Button, Upload, message } from 'antd';
const FromComponent = (props)=>{
const [fileList, setFileList] = useState([]); // 上传成功文件列表
const [fileDateList, setFileDateList] = useState([]);// 上传文件列表(预览)
// 上传文件配置
const uploadProps = {
name: 'file',
maxCount:10,
withCredentials: true, // 上传请求时是否携带 cookie
fileList: fileDateList, // 已经上传的文件列表
action: requestConfig.certificate, // 上传的地址
accept:".doc, .docx, .pdf, .jpg, .png", // 接受上传的文件类型
headers: {'X-Access-Token': sessionStorage['X-Access-Token'] ?? ''},
beforeUpload: file => { // 文件上传前校验
var sameList = fileDateList.filter(item => item.lastModified == file.lastModified);
if (sameList.length >= 1) {
message.error(`请勿重复上传同一文件`);
return Upload.LIST_IGNORE;
} else if (fileDateList.length == 10) {
message.error(`文件数量最多上传10个`);
} else if (file.size > 10240000) {
message.error(`文件过大,请重新选择10M以内的文件`);
return Upload.LIST_IGNORE;
} else if(!['image/png','image/jpeg','application/pdf','application/msword']
.includes(file.type)) {
message.error(`文件格式错误`);
return Upload.LIST_IGNORE;
} else if(file.name.length > 50) {
message.error(`请选择名称在50字符以内的文件`);
return Upload.LIST_IGNORE;
} else {
return true;
}
},
onChange(info) {
if (info.file.status === 'done') { // 新增文件
setFileList([...fileList,{
fileName: info.file.name,
fileUrl: info.file.response.data,
}]);
if (info.file.response.returnCode == '17000') {
message.success('文件上传成功');
} else {
message.error('文件上传失败');
}
} else if (info.file.status === 'removed') { // 删除文件
const index = fileList.findIndex(item =>
item.name === info.file.name);
fileList.splice(index, 1);
setFileList(fileList);
}
let list = [...info.fileList];
list = list.map(file => {
if (file.response) {
file.url = file.response.data;
}
return file;
});
setFileDateList([...list]);
},
onPreview(file){ // 文件预览
if (['image/png','image/jpeg','application/pdf'].includes(file.type)) {
var link = document.createElement('a');
link.target = '_black';
link.href = file.url;
link.click();
} else {
bizFuns.downLoadFile({
item:{
fileName: file.name,
fileUrl: file.url,
}
})
}
}
};
return <Upload>
<Button icon={<UploadOutlined/>}>上传文件</Button>
<p style={{color:"gray"}}>支持扩展名: .doc .docx .pdf .jpg .png </p>
</Upload>
}
export default FromComponent;
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END