react封装图片上传组件
支持表单受控和非受控使用,基于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,
        }}
react封装图片上传组件的更多相关文章
- 微信小程序简单封装图片上传组件
		
微信小程序简单封装图片上传组件 希望自己 "day day up" -----小陶 我从哪里来 在写小程序的时候需要上传图片,个人觉得官方提供的 Uploader 组件不是太好用, ...
 - React后台管理手动封装图片上传组件
		
分为两个文件夹,index.js(逻辑文件) styled.js(样式文件) index.js文件,编写完成之后在对应的地方引入即可 import React from "react&quo ...
 - 基于Node的React图片上传组件实现
		
写在前面 红旗不倒,誓把JavaScript进行到底!今天介绍我的开源项目 Royal 里的图片上传组件的前后端实现原理(React + Node),花了一些时间,希望对你有所帮助. 前端实现 遵循R ...
 - 分享一个react 图片上传组件 支持OSS 七牛云
		
react-uplod-img 是一个基于 React antd组件的图片上传组件 支持oss qiniu等服务端自定义获取签名,批量上传, 预览, 删除, 排序等功能 需要 react 版本大于 v ...
 - vue图片上传组件
		
前言:很多项目中都需要用到图片上传功能,而其多处使用的要求,为了避免重复造轮子,让我决定花费一些时间去深入了解,最终封装了一个vue的图片上传组件.现将总结再次,希望有帮助. Layout <d ...
 - Jquery图片上传组件,支持多文件上传
		
Jquery图片上传组件,支持多文件上传http://www.jq22.com/jquery-info230jQuery File Upload 是一个Jquery图片上传组件,支持多文件上传.取消. ...
 - H5拍照、选择图片上传组件核心
		
背景 前段时间项目重构,改成SSR的项目,但之前用的图片选择上传组件不支持SSR(server-side-render).遂进行了调研,发现很多的工具.但有的太大,有的使用麻烦,有的不满足使用需求.决 ...
 - 图片上传组件webuploader
		
前端组件webuploader 当时也是搞了很久参考这种demo,但是没记.现在事后大致总结下.直接上大概代码(我使用asp.net MVC来做的): 执行顺序:(get)Record/Add——A ...
 - vux-uploader  图片上传组件
		
1.网址:https://github.com/greedying/vux-uploader 2.安装 npm install vux-uploader --save npm install --sa ...
 - 【antd Vue】封装upload图片上传组件(返回Base64)
		
最近需要把上传的图片信息存储到数据库,以base64的方式,需要重新封装一下antd的upload组件 1. 使用方法 引入组件然后配置一下即可使用,配置项包括 defaultImageList,需要 ...
 
随机推荐
- P5733 自动修正
			
字符串题解第一弹~ [千万不能错过的原题连接](https://www.luogu.com.cn/problem/P5733) 今天就研究一下这道自动修正问题哈 首先,我们看到了小写转大写的时候,就知 ...
 - top单核与32C--CPU爆表
			
linux的cpu使用频率是根据cpu个数和核数决定的 top, 然后你按一下键盘的1,这就是单个核心的负载,不然是所有核心的负载相加,自然会超过100 单核为100%,服务器是32核的,下面基本用了 ...
 - ADC采样信号RMS测量值的Verilog实现
			
术语"RMS"代表"Root-Mean-Squared".大多数书籍将此定义为"产生与等效直流电源相同的加热效果的交流电量",或者沿着这些线 ...
 - jmeter使用Java开发自定义函数
			
一.前置条件(对jmeter进行二次开发) 本篇通过抽象类AbstractFunction来实现: 1.JMeter提供了接口给用户进行二次开发,其中接口可通过引入 ApacheJMeter_comp ...
 - DataTable中排序的开启与禁用
			
1. 2. orderable设置成true会打开排序功能,设置为false会禁用排序功能.
 - Python发送飞书消息
			
#!/usr/bin/python3.8 # -*- coding:UTF-8 -*- import os, sys sys.path.append(os.path.dirname(os.path.a ...
 - 正则表达式re.compile()的使用
			
re 模块提供了不少有用的函数,用以匹配字符串,比如: compile 函数match 函数search 函数findall 函数finditer 函数split 函数sub 函数subn 函数re ...
 - 关于 echarts 使用 geo 制作地图 tooltip 不显示问题(转)
			
原文地址 我之前遇到过这问题,单独设置 tooltip 没效果,geo 下面也有 tooltip 属性,但是也不管用,网上查了一下说 geo 不支持 tooltip 提示框显示,就自己根据 echar ...
 - IDEA debug时拷贝数据 Evaluate Expression窗口
			
今日份鸡汤:别人再好,也是别人.自己再不堪,也是自己,独一无二的自己.只要努力去做最好的自己,一生足矣.为自己的人生负责,为自己的梦想买单. 用IDEA调试时候经常需要拷贝变量值出来排查,特别是数据结 ...
 - JiaoZiVideoPlayer模拟用户点击,切换播放引擎!~
			
默认播放及模拟用户点击播放按钮 jzvideoPlayerStandard.startButton.performClick() 切换播放引擎及使用Ijkplayer JZVideoPlayer.se ...