当前位置: 首页 > news >正文

Antd中Upload组件封装及使用:

1.Upload上传组件功能:

  •   文件校验 :

        文件格式校验/文件大小校验/上传文件总个数校验

  •   相关功能 :

         拖拽功能/上传到远程(七牛)/文件删除及下载

2.组件效果展示:

3.疑难点及解决方案:

  Promise.all多文件并行上传到远程(七牛云):

 (1)在beforeUpload钩子函数中获取token

 (2)循环fileList文件列表,使用fetch将所有文件上传到七牛,并将结果包装成Promise return出去

 (3)待所有文件上传成功后,通过Promise.all获取并存储结果,并通过useEffect及时将七牛返回的结果添加到fileList文件列表中。

 (4)注:由于一次上传多个文件时,beforeUpload钩子函数会执行多次,需要使用debounce进行防抖。

const [promiseAllResult, setPromiseAllResult] = useState<UploadFile[]>([]);const beforeUpload: UploadProps["beforeUpload"] = (file, fileList) => {debouncedBeforeUpload(fileList);return false;
};const debouncedBeforeUpload = debounce(async fileList => {...const res = await getQiniuTokenApi();const uploadPromises = fileList.map(async (file: any) => {return new Promise((resolve, reject) => {const formData = new FormData();formData.append("file", file);formData.append("token", res.data?.upToken || "");fetch("https://upload.qiniup.com/", {method: "POST",body: formData}).then(response => {if (response.status === 200) {return response.json().then(data => {// 返回包含文件信息和响应数据的对象resolve({uid: file.uid,url: "https://" + res.data?.domain + "/" + data.key + "?attname=" + file.name,filePreviewUrl: "https://" + res.data?.domain + "/" + data.key});}).catch(() => {reject(new Error("Upload failed"));});} else {reject(new Error("Upload failed"));}}).catch(error => reject(error));});});Promise.all(uploadPromises).then(res => {setPromiseAllResult(res);message.success("文件上传成功");}).catch(() => message.error("文件上传失败"));
});useEffect(() => {if (promiseAllResult && promiseAllResult.length > 0 && fileList && fileList.length > 0) {fileList.forEach(item => {const findResult = promiseAllResult.find(file => file.uid === item.uid);if (findResult) {// @ts-ignoreitem.filePreviewUrl = findResult.filePreviewUrl;item.url = findResult.url;}});}
}, [promiseAllResult]);

4.完整代码:

  • 封装文件上传组件:

      src/component/Upload/index.tsx:

import { forwardRef, useImperativeHandle, useState, useEffect } from "react";
import { Upload, message } from "antd";
import { InboxOutlined } from "@ant-design/icons";
import type { UploadFile, UploadProps } from "antd";
import { getQiniuTokenApi } from "@/api/modules/assetManagement";
import { debounce } from "lodash";
const { Dragger } = Upload;
interface UploadComType {maxCount?: number;accept?: string[];size?: number;multiple?: boolean;
}
const UploadCom = forwardRef(({maxCount = 3,accept = [".doc",".docx",".xml","application/msword","application/vnd.openxmlformats-officedocument.wordprocessingml.document","application/pdf","image/png","image/jpeg"],size = 2,multiple = true}: UploadComType,ref: any) => {const [fileList, setFileList] = useState<UploadFile[]>([]);const [promiseAllResult, setPromiseAllResult] = useState<UploadFile[]>([]);useEffect(() => {if (promiseAllResult && promiseAllResult.length > 0 && fileList && fileList.length > 0) {fileList.forEach(item => {const findResult = promiseAllResult.find(file => file.uid === item.uid);if (findResult) {// @ts-ignoreitem.filePreviewUrl = findResult.filePreviewUrl;item.url = findResult.url;}});}}, [promiseAllResult]);useImperativeHandle(ref, () => ({getFileList: () => {return fileList;},parentSetList: (list: UploadFile[]) => {setFileList(list);}}));const onRemove = (file: UploadFile) => {const list = fileList.filter(item => item.uid !== file.uid);setFileList(list);};const beforeUpload: UploadProps["beforeUpload"] = (file, fileList) => {debouncedBeforeUpload(fileList);return false;};const debouncedBeforeUpload = debounce(async fileList => {let newFileList = fileList.filter((file: any) => {// 上传中的文件不进行校验if (file.status === "uploading") return true;// 校验文件类型const isFileTypeValid = accept.includes(file.type || "");if (!isFileTypeValid) {message.error(`${file.name} 不是允许的文件类型`);return false;}// 校验文件大小const isFileSizeValid = (file.size || 0) <= size * 1024 * 1024;if (!isFileSizeValid) {message.error(`${file.name} 超过最大文件大小限制 (${size}MB)`);return false;}return true;});if (newFileList.length === 0) {message.warning("没有符合要求的文件可上传");return false;}const res = await getQiniuTokenApi();const uploadPromises = newFileList.map(async (file: any) => {return new Promise((resolve, reject) => {const formData = new FormData();formData.append("file", file);formData.append("token", res.data?.upToken || "");fetch("https://upload.qiniup.com/", {method: "POST",body: formData}).then(response => {if (response.status === 200) {return response.json().then(data => {// 返回包含文件信息和响应数据的对象resolve({name: file.name,size: file.size,uid: file.uid,type: file.type,status: file.status,url: "https://" + res.data?.domain + "/" + data.key + "?attname=" + file.name,filePreviewUrl: "https://" + res.data?.domain + "/" + data.key});}).catch(() => {reject(new Error("Upload failed"));});} else {reject(new Error("Upload failed"));}}).catch(error => reject(error));});});Promise.all(uploadPromises).then(res => {setPromiseAllResult(res);message.success("文件上传成功");}).catch(() => message.error("文件上传失败"));});const handleChange: UploadProps["onChange"] = ({ fileList }) => {let newFileList = fileList;if (newFileList.length > maxCount) {message.warning(`最多可上传${maxCount}个文件`);newFileList = newFileList.slice(-maxCount);}setFileList(newFileList);};const uploadProps: UploadProps = {name: "file",onRemove,beforeUpload: beforeUpload,multiple: multiple,onChange: handleChange,accept: accept.join(",")};return (<div><Dragger {...uploadProps} fileList={fileList}><p className="ant-upload-drag-icon"><InboxOutlined /></p><p className="ant-upload-text">Click or drag file to this area to upload</p><p className="ant-upload-hint">Support for a single or bulk upload. Strictly prohibited from uploading company data or other banned files.</p></Dragger></div>);}
);
export default UploadCom;
  • 使用文件上传组件:
import UploadCom from "@/components/Upload/index";const uploadComRef = useRef<any>(null);<UploadCom ref={uploadComRef} />//获取组件中的文件
const file = uploadComRef.current?.getFileList();//给组件中的文件赋初始值
uploadComRef.current?.parentSetList(files);

http://www.xdnf.cn/news/581437.html

相关文章:

  • 【Redis】三、在springboot中应用redis
  • python实现web请求与回复
  • 水库大坝、坝肩混凝土面板变形及岸坡位移多断面多测点安全监测新途径——变焦视觉位移监测仪
  • 在线时间戳(Unix TimeStamp)转换器
  • 739. 每日温度
  • 单片机如何快速实现查看实时数据
  • [Git] 基本操作及用户配置
  • CSR矩阵 矩阵压缩
  • 深入探究C++11的核心特性
  • [Harmony]网络请求
  • 【FAQ】HarmonyOS SDK 闭源开放能力 —Live View Kit (3)
  • HarmonyOS NEXT~React Native 在鸿蒙系统上的应用与实践
  • 企业网站架构部署与优化第4章Nginx核心功能
  • Axios中POST、PUT、PATCH用法区别
  • 服务器硬盘分类
  • 小白的进阶之路系列之三----人工智能从初步到精通pytorch计算机视觉详解下
  • C# 使用 Source Generation 提升 System.Text.Json 性能
  • 职坐标嵌入式MCU/DSP与RTOS开发精讲
  • Android logcat命令汇总
  • Elasticsearch 写入性能优化有哪些常见手段?
  • c++11特性——lambda对象、包装器
  • Strands Agents:AWS开源Agent框架的技术与应用全景
  • MySQL 索引失效及其解决办法
  • 全面学习c++类与对象(中)(非常重要)(析构构造拷贝函数赋值运算符重载等等)
  • 养生攻略:五步打造健康生活
  • Three.js搭建小米SU7三维汽车实战(1)搭建开发环境
  • 腾讯云媒体AI解码全球视频出海智能密码
  • 替代云数据库的本地方案:MySQL+phpMyAdmin的远程管理与跨网络访问技术
  • Windows下PyCharm2025的运行卡顿的问题
  • 介绍一下 MVCC