相关参考
- FormData:https://developer.mozilla.org/zh-CN/docs/Web/API/FormData
- FileReader:https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader
前言
antdesign的upload组件:https://ant.design/components/upload-cn/#components-upload-demo-basic
需要一个接口直接传给服务端,针对一些简单的场景可以使用,但如果是一个交互多点场景,可能有点不适合,所以下面进入正文视觉稿

代码实现
具体交互细节以实际交互为准
import { useState, useEffect } from "react";import { Modal, Button, message } from "antd";import { LoadingOutlined, PaperClipOutlined } from "@ant-design/icons";import { UploadFile } from "../components";import * as PartnerAction from "../api/request/partner";import "@css/components/upload-partner.less";export default ({ fetchList }: any) => {const [visible, setVisible] = useState<boolean>(false);const [btnLoading, setBtnLoading] = useState<boolean>(false);const [uploadDisabled, setUploadDisabled] = useState<boolean>(true);const [uploadFileInfo, setUploadFileInfo] = useState<any>({});// 确认上传const onFinish = async () => {try {const formData = new FormData();formData.append("file", uploadFileInfo.file);setBtnLoading(true);const { success }: any = await PartnerAction.uploadFile(formData);setBtnLoading(false);if (!success) return;await fetchList();setVisible(false);message.success("导入成功");onUploadFileChange({status: "none",});} catch (error) {console.log(error);}};// 【X】关闭按钮const onModalClose = (): void => {if (btnLoading) return;setUploadDisabled(true);setVisible(false);setUploadFileInfo({status: "none",});};const onUploadFileChange = (item: any) => {setUploadFileInfo(item);};useEffect(() => {if (uploadFileInfo.status === "none" ||uploadFileInfo.status === "progress") {setUploadDisabled(true);}if (uploadFileInfo.status === "done") {setUploadDisabled(false);}}, [uploadFileInfo]);return (<><Button onClick={() => setVisible(true)}>文件上传</Button><Modaltitle="文件上传"centeredvisible={visible}maskClosable={false}keyboard={false}onCancel={onModalClose}okButtonProps={{ disabled: uploadDisabled, loading: btnLoading }}cancelButtonProps={{ disabled: uploadDisabled }}onOk={onFinish}><UploadFileuploadDisabled={btnLoading}uploadData={uploadFileInfo}onUploadFileChange={onUploadFileChange}/><>{uploadFileInfo.status === "none" ? (<span className="file_prefix">支持扩展名:.xls .xlsx</span>) : (<p className="upload_file">{uploadFileInfo.status === "progress" && (<LoadingOutlined className="upload_icon" />)}{uploadFileInfo.status === "done" && (<PaperClipOutlined className="upload_icon" />)}{(uploadFileInfo.status === "done" ||uploadFileInfo.status === "progress") &&`${uploadFileInfo?.file?.name}`}</p>)}</></Modal></>);};
import { useState, useEffect, useRef } from "react";import { UploadOutlined } from "@ant-design/icons";import { Button, message } from "antd";import { beforeUploadFile } from "../utils";import "@css/components/upload-file.less";export default ({ uploadDisabled = false, onUploadFileChange }: any) => {const uploadFileRef = useRef<any>({});const [disabled, setDisabled] = useState<boolean>(uploadDisabled);const [fileData, setFileData] = useState<any>({status: "none",});const onUploadFile = (e: any) => {const file = e.target.files[0];if (!beforeUploadFile(file)) return;const fileReader: any = new FileReader();fileReader.onload = () => {const data = {...fileData,file,status: "done",};setFileData(data);setDisabled(false);onUploadFileChange(data);};fileReader.onerror = () => {message.error("文件失败,请重新上传:", fileReader.error);onUploadFileChange({status: "none",});setDisabled(false);};fileReader.onprogress = () => {setFileData({status: "progress",});onUploadFileChange({status: "progress",});setDisabled(true);};fileReader.readAsArrayBuffer(file);};const onUploadClick = () => {uploadFileRef.current.click();};// 重置input的value为空/*** faq:使用input[type=file] 实现文件上传功能,通过onchange事件触发js代码,这个时候第一次上传是完全没问题的,当你第二次上传文件时,如果是不同于上一次上传文件的话是可以正常上传的,不过如果你选择的还是上一个文件,也就是两次上传的文件重复了,那么就会上传失败。* input是通过onchange事件来触发js代码的,由于两次文件是重复的,所以这个时候onchange事件是没有触发到的。* how:读取文件后,记得把input的value重新设置为空即e.target.value=''*/const onResetInputValue = (e: any) => {(e.target as HTMLInputElement).value = "";};useEffect(() => {onUploadFileChange({status: "none",});}, []);return (<><div className="upload_container"><Button disabled={disabled} onClick={onUploadClick}><UploadOutlined />选择文件</Button><inputref={uploadFileRef}type="file"onClick={(e) => onResetInputValue(e)}className="upload_input"onChange={onUploadFile}/></div></>);};
export const EXCEL_SUFFIX_REG = /(xls|xlsx)(\?.*)?/;// 文件上传校验export const beforeUploadFile = (file: any): boolean | undefined => {const temp = file?.name?.split(".");const suffix = temp[temp.length - 1].toLowerCase();if (!EXCEL_SUFFIX_REG.test(suffix)) {message.warning("仅支持导入.xls .xlsx扩展名文件");return false;}return true;};
