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);
相关文章:

Antd中Upload组件封装及使用:
1.Upload上传组件功能: 文件校验 : 文件格式校验/文件大小校验/上传文件总个数校验 相关功能 : 拖拽功能/上传到远程(七牛)/文件删除及下载 2.组件效果展示: 3.疑难点及解决方案: Promise.all多文件并行上传到远程(七牛云): (1)在beforeUpload钩子函数中获取token (2)循环fi…...

Linux环境基础开发工具->vim
引入:vim是什么? vs叫作继承开发环境,我们可以在里面编辑代码,调式代码,运行代码....这种叫集成开发环境;而vim只用来编辑代码,也就是类似于在windows上打开一个记事本来写代码的操作 集成开发…...

跳板问题(贪心算法+细节思考)
首先直接看题: 这题直接贪心其实问题不大: 下面先展示我的一个错误代码: # include<iostream> # include<vector> # include<algorithm>using namespace std;int main() {int N,M;cin>>N>>M;vector<vecto…...

RuoYi前后端分离框架集成UEditorPlus富文本编辑器
一、背景 采用若依框架搭建了一个小型的电子书项目,项目前端、后端、移动端就一人,电子书的章节内容是以富文本内容进行呈现的,产品设计人员直接给了一个第三方收费的富文本编辑器截图放到开发文档中,提了一沓需求点,概况下来就是要做成下图中的样子。作为一个后端开发人…...

IPD流程落地:项目任务书Charter开发
目录 简介 第一个方面,回答的是Why的问题。 第二点,要回答做什么的问题,也就是产品定义What的问题。 第三点就是要回答执行策略与计划的问题,也就是How、When、Who的问题。 第四点是对上述这些分析的总结分析,要为…...

Vue 2 混入 (Mixins) 的详细使用指南
1.基本概念 混入 (Mixins) 是 Vue 2 中用于组件代码复用的重要特性,它允许你将可复用的功能分发到多个组件中。 混入是一种灵活的代码复用方式,可以包含任意组件选项(data、methods、生命周期钩子等)。当组件使用混入时ÿ…...
day020-sed和find
文章目录 1. sed1.1 查找、过滤文本1.1.1 根据行号取行1.1.2 根据行号取范围1.1.3 过滤出指定行1.1.4 过滤出指定范围内容 1.2 替换文件内容1.2.1 将文件中虚拟用户命令解释器替换成/bin/bash1.2.2 修改原文件并备份1.2.3 为每行开头加上# 1.3 反向引用(后向引用&am…...
OpenGL Chan视频学习-4 Vertex Buffers and Drawing a Triangle in OpenGL
一、视频链接 【最好的OpenGL教程之一】https://www.bilibili.com/video/BV1MJ411u7Bc?p5&vd_source44b77bde056381262ee55e448b9b1973 二、相关网站 docs.gl 三、代码整理 c #include <GL/glew.h> #include <GLFW/glfw3.h>#include<iostream>int…...
数据库事务的四大特性(ACID)
一、前言 在现代数据库系统中,事务(Transaction)是确保数据一致性和完整性的重要机制。事务的四大特性——原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)…...
网络安全全知识图谱:威胁、防护、管理与发展趋势详解
1 网络安全基础概念 1.1 什么是网络安全 网络安全是指通过技术、管理和法律等手段,保护计算机网络系统中的硬件、软件及其系统中的数据,不因偶然的或者恶意的原因而遭受到破坏、更改、泄露,确保系统连续可靠正常地运行,网络服务不…...

FreeRTOS 在物联网传感器节点的应用:低功耗实时数据采集与传输方案
FreeRTOS 在物联网传感器节点的应用:低功耗实时数据采集与传输方案 二、FreeRTOS 任务划分与优先级设计 任务名称优先级执行周期功能描述Sensor_Collect3100ms多传感器数据采集与预处理Data_Process2事件驱动数据滤波/压缩/异常检测LoRa_Transmit41s低功耗长距离数…...
解决 iTerm2 中 nvm 不生效的问题(Mac 环境)
解决 iTerm2 中 nvm 不生效的问题(Mac 环境) 标题 《为什么 iTerm2 无法使用 nvm?—— 解决 Mac 终端环境变量冲突指南》 问题描述 许多开发者在 Mac 上使用 nvm 管理 Node.js 版本时,发现: 原生终端:n…...

Linux环境下基于Docker安装 PostgreSQL数据库并配置 pgvector
文章目录 1 docker-compose 安装 PostgreSQL 容器内安装 pgvector1.1 基于 docker-compose 安装 PostgreSQL 数据库1.2 容器内配置 pgvector 2. docker-compose Dockerfile 形式直接配置PostgreSQL数据库及 pgvector参考资料 PostgreSQL是一种功能强大的开源关系数据库管理系…...

(9)-java+ selenium->元素定位之By name
1.简介 上一篇已经介绍了通过id来定位元素,继续介绍其他剩下的七种定位方法中的通过name来定位元素。本文来介绍Webdriver中元素定位方法之By name,顾名思义,就是我们想要定位的目标元素节点上,有一个name ="value"的属性,这样我们就可以通过name的value直接去…...

深浅拷贝?
一、定义: 浅拷贝:只复制对象的第一层属性,若第一层属性是引用类型(如对象、数组),则复制其内存地址,修改拷贝后的嵌套对象会影响原对象。 深拷贝:递归复制对象的所有层级…...

Beckhoff PLC 功能块 FB_CTRL_ACTUAL_VALUE_FILTER (模拟量滤波)
1. 功能块概览 名称:FB_CTRL_ACTUAL_VALUE_FILTER(实际值滤波控制功能块)。作用:对测量输入值进行合理性检查( plausibility check )和滤波处理,防止异常跳变(如传感器信号突变&…...
Mysql在SQL层面的优化
以下是MySQL在SQL层面的优化方法及详细案例,结合实际场景说明如何通过调整SQL语句提升性能: 1. 确保索引有效使用 案例:订单状态查询优化 问题SQL: SELECT * FROM orders WHERE status shipped AND create_time > 2023-01-…...
JVM规范之栈帧
JVM规范之栈帧 前言正文概述局部变量表操作数栈动态链接 总结参考链接 前言 上一篇文章了解了JVM规范中的运行时数据区: JVM规范之运行时数据区域 其中,栈是JVM线程私有的内存区,栈中存储的单位是帧(frames)ÿ…...

【C++指南】string(四):编码
💓 博客主页:倔强的石头的CSDN主页 📝Gitee主页:倔强的石头的gitee主页 ⏩ 文章专栏:《C指南》 期待您的关注 引言 在 C 编程中,处理字符串是一项极为常见的任务。而理解字符串在底层是如何编码存储的&…...

深度学习之序列建模的核心技术:LSTM架构深度解析与优化策略
LSTM深度解析 一、引言 在深度学习领域,循环神经网络(RNN)在处理序列数据方面具有独特的优势,例如语音识别、自然语言处理等任务。然而,传统的 RNN 在处理长序列数据时面临着严重的梯度消失问题,这使得网…...

AI量化交易是什么?它是如何重塑金融世界的?
第一章:证券交易的进化之路 1.1 从喊价到代码:交易方式的革命性转变 在电子交易普及之前,证券交易依赖于交易所内的公开喊价系统。交易员通过手势、喊话甚至身体语言传递买卖信息,这种模式虽然直观,但效率低下且容易…...

分布式事务处理方案
1. 使用Seata框架解决 1.1 XA 事务 1.1.1 XA整体流程 第一阶段 RM1开启XA事务-> 执行业务SQL -> 上报TC执行结果RM2开启XA事务-> 执行业务SQL -> 上报TC执行结果 第二阶段 TC根据 RM上报结果通知RM一起提交/回滚XA事务 1.1.2 XA特点 XA 模式必须要有数据库的支…...

CVE-2024-36467 Zabbix权限提升
漏洞描述 在Zabbix中,具有API访问权限的已认证用户(例如具有默认用户角色的用户)可以通过调用user.update API接口,将自己添加到任何用户组(如Zabbix管理员组)。然而,用户无法添加到已被禁用或…...

Dify中的自定义模型插件开发例子:以xinference为例
本文使用Dify v1.0.0-beta.1版本。模型插件结构基本是模型供应商(模型公司,比如siliconflow、xinference)- 模型分类(模型类型,比如llm、rerank、speech2text、text_embedding、tts)- 具体模型(…...
crud方法命名示例
以下是基于表名dste_project_indicator(项目指标表)的完整命名示例,覆盖各类增删改查场景: 1. 表名与实体类映射 // 表名:dste_project_indicator // 实体类:DsteProjectIndicatorEntity public class Ds…...

尚硅谷redis7 33-36 redis持久化之RDB优缺点及数据丢失案例
官网说明优点: RDB是Redis数据的一个非常紧凑的单文件时间点表示,RDB文件非常适合备份。例如,您可能希望在最近的24小时内每小时旧档一次RDB文件,并在30天内每天保存一个RDB快照,这使您可以在发生来难时轻松恢复不同版本的数据集。RDB非常适合灾难恢复,它是一个可以…...
No such file or directory: ‘ffprobe‘
目录 详细信息: 解决方法: No such file or directory: ffprobe 详细信息: File "/usr/local/lib/python3.10/dist-packages/framepump/framepump.py", line 168, in get_duration return float(ffmpeg.probe(video_path)[form…...

计算机网络-WebSocket/DNS/Cookie/Session/Token/Jwt/Nginx
文章目录 WebSocketDNS什么是dns域名解析底层协议 cookie/sessionToken/JWTNginx WebSocket 一种网络通信协议,允许在单个 TCP(半双工) 连接上进行全双工通信(客户端和服务器可同时双向传输数据)。 HTTP是基于请求-响…...
功能“递归模式”在 C# 7.3 中不可用,请使用 8.0 或更高的语言版本的一种兼容处理方案
原程序: internal class ControllerParameterCreator : IParameterCreator {private Controller controller;public ControllerParameterCreator(Controller controller){this.controller controller;}public Parameter CreateSystem(string name, int unused){re…...
第4章-操作系统知识
存储管理 固定分区:一种静态分区方式请求分页存储管理覆盖技术:覆盖技术是指让作业中不同时运行的程序模块共同使用同一主存区域。...