支持表单受控和非受控使用,基于antd upload 进行的二次封装,
使用场景如下图:
1.组件文件夹
2. index.tsx贴代码
import React, { useEffect, useMemo, useState } from 'react'; import { ImageFilesWrapper } from './style'; import type { RcFile, UploadProps } from 'antd/es/upload'; import type { UploadFile } from 'antd/es/upload/interface'; import { message, Modal } from 'antd'; import icon from './img/uil_image_plus.svg'; import { uploadImageFileWithNoToken } from 'requests/fileUpload-requests'; import { addUriPrefixIfNeeded } from 'utils/requests/utils'; // 转化url import { v4 } from 'uuid'; interface Iprops { onChange?: (data) => void; onRemove?: (data) => void; maxCount?: number; //可上传的图片张数 value?: string[]; // 表单默认值 multiple?: boolean; } interface Iflie { uid: string; status: string; url: string; } //图片上传 export default function ImageUpload(props: Iprops) { const { onChange, multiple, value, onRemove, maxCount } = props; // 处理 表单传入的值 const defaultList = useMemo(() => { if (value?.length) { let list: Iflie[] = []; value?.map(v => { list.push({ uid: v4(), status: 'done', url: addUriPrefixIfNeeded(v), }); }); return list; } }, [value]); const [fileList, setFileList] = useState<any>(defaultList || []); const [previewVisible, setPreviewVisible] = useState(false); const [previewImage, setPreviewImage] = useState(''); const [previewTitle, setPreviewTitle] = useState(''); const handleCancel = () => setPreviewVisible(false); const handleChange: UploadProps['onChange'] = async ({ fileList: newFileList, }) => { setFileList(newFileList || []); let urlList: any = []; newFileList?.map(v => { if (v?.response?.fileId || v.url) { urlList.push(v?.response?.fileId || v.url); } }); onChange?.(urlList); }; const getBase64 = (file: RcFile): Promise<string> => new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => resolve(reader.result as string); reader.onerror = error => reject(error); }); const handlePreview = async (file: UploadFile) => { if (!file.url && !file.preview) { file.preview = await getBase64(file.originFileObj as RcFile); } setPreviewImage(file.url || (file.preview as string)); setPreviewVisible(true); setPreviewTitle( file.name || file.url!.substring(file.url!.lastIndexOf('/') + 1), ); }; async function uploadHeadImg(info) { try { const res = await uploadImageFileWithNoToken(info.file); if (res) { message.info('上传成功'); info.onSuccess(res, info.file); // 上传成功触发 } else { message.error('上传失败'); } } catch (error) { info.onError(error, undefined, info.file); // 上传失败触发 // @ts-ignore message.error(error?.message || '上传失败'); console.error(error); } } return ( <> <ImageFilesWrapper listType="picture-card" fileList={fileList} onPreview={handlePreview} multiple={multiple} maxCount={maxCount} accept=".png,.jpg,.jpeg" beforeUpload={file => { if (!['image/png', 'image/jpg', 'image/jpeg'].includes(file.type)) { message.info('仅支持上传png/jpg/jpeg格式的图片'); } return ['image/png', 'image/jpg', 'image/jpeg'].includes(file.type); }} onChange={handleChange} onRemove={(data: any) => { console.log(data, 'data,remove'); if (data?.disabled) { return Promise.resolve(false); } else { return onRemove ? onRemove(data) : Promise.resolve(true); } }} customRequest={uploadHeadImg} > {((maxCount && fileList?.length < maxCount) || !maxCount) && ( <div className="imgButton"> <img src={icon} alt="" /> <div>添加图片</div> </div> )} </ImageFilesWrapper> <Modal open={previewVisible} title={previewTitle} footer={null} onCancel={handleCancel} > <img alt="example" style={{ width: '100%' }} src={previewImage} /> </Modal> </> ); }
3.样式代码
import { Upload } from 'antd'; import styled from 'styled-components/macro'; export const ImageFilesWrapper = styled(Upload)` text-align: left; .adm-image-uploader-cell { width: 60px; height: 60px; line-height: 60px; } .adm-image-uploader { } .upload-finsh { color: #0ebd73; margin-right: 10px; } .imgButton { width: 100%; display: flex; align-items: center; justify-content: center; color: var(--primary-color); img { margin-right: 5px; } } `;
4.页面表单使用
<Form.Item label="人员头像" name="headerImg" rules={[ { required: false, }, ]} valuePropName="value" trigger="onChange" > <ImageUpload maxCount={1} /> </Form.Item>
表单初始值赋:
initialValues={{ headerImg: infoToEdit?.avatarUrl ? [infoToEdit.avatarUrl] : undefined, }}
标签:封装,url,image,react,file,error,import,上传,const From: https://www.cnblogs.com/shyhuahua/p/17150368.html