带你封装一个上传图片组件(ant design+react)

目录

需求实现

实现效果

代码封装

UploadImage组件

 备注

 BaseUploadImage组件

index.less

样式文件

父组件引用


需求实现

1可以支持上传最多九张图片

2图片支持预览 替换 删除

3支持自定义上传文件大小 格式 未上传提示

实现效果

 

 

 

代码封装

UploadImage组件

 * @Description: 公共上传图片* @param {Array} type 图片格式。默认类型为png,jpeg* @param {Number} size 图片限制大小 默认大小为8M* @param {String} errorTypeMsg 图片格式错误文字提示* @param {String} errorTypeMsg 图片大小错误文字提示* @param {Function} handleFetchUrl 选中图片后回调函数* @param {String} uploadUrl 上传图片请求的url,默认为admin/fileUpload* @param {String} iconText 按钮文字* @param {Object} style 样式* @param {String} value 当前图片地址*/
import React, { Component } from 'react';
import { Tooltip, Upload, Icon, message, Modal, Divider, Spin } from 'antd';
import styles from './index.less';
import { fileUpload } from '@/services/common/upload';export default class UploadImage extends Component {constructor(props) {super(props);this.state = {visible: false,shadow: false,loading: false,};}componentWillMount() {this.props.onRef && this.props.onRef(this);}/*** @description: 上传前格式大小等校验*/beforeUpload = (file) => {/*** @description: 父组件传入的参数* @param {Array} type 图片格式。默认类型为png,jpeg* @param {Number} size 图片限制大小 默认大小为8M* @param {String} errorTypeMsg 图片格式错误文字提示* @param {String} errorSizeMsg 图片大小错误文字提示* @param {Function} checkSize 文件大小校验方式*/let {type = ['image/jpeg', 'image/png', 'image/gif'],size,errorTypeMsg,errorSizeMsg,checkSize,} = this.props;size ? (size = size) : (size = 8);if (checkSize) {size = checkSize(file.type);}const isJpgOrPng = type.includes(file.type);if (!isJpgOrPng) {message.error(errorTypeMsg || '图片/视频格式错误!请上传jpeg/png/gif格式图片或avi/mp4格式视频');}const isLt8M = file.size < size * 1024 * 1024;if (!isLt8M) {message.error(errorSizeMsg || '图片/视频大小限制' + size + 'M!');}return isJpgOrPng && isLt8M;};handleUpload = ({ file }) => {/*** @description:* @param {Function} handleFetchUrl 选中图片后回调函数* @param {String} uploadUrl 上传图片请求的url,默认为admin/fileUpload*/const { dispatch, uploadUrl, handleFetchUrl } = this.props;const formData = new FormData();formData.append('file', file);formData.append('fileCode', 'PIC');this.setState({ loading: true });const upload = async (record) => {let upUrl = uploadUrl || fileUpload;try {const response = await upUrl(formData);if (response.returnCode === 0) {if (handleFetchUrl && typeof handleFetchUrl === 'function') {handleFetchUrl(response.data, file.type);}message.success('上传成功');//上传成功的回调this.props.handleUploadImage && this.props.handleUploadImage();}this.setState({ loading: false });} catch (error) {console.log(error, 'error');this.setState({ loading: false });}};upload();// dispatch({//   type: uploadUrl || 'admin/fileUpload',//   payload: formData,//   callback: (response) => {//     if (response.returnCode === 0) {//       if (handleFetchUrl && typeof handleFetchUrl === 'function') {//         handleFetchUrl(response.data, file.type);//       }//       message.success('上传成功');//     }//   },// });};/*** @description: 改变visible* @param {*}*/handleSetVisible = (val, event) => {this.setState({visible: val,});if (event) {event.stopPropagation();}};/*** @description: 改变image上的阴影显示*/setShadow = (val) => {this.setState({shadow: val,});};/*** @description: 删除图片*/handleDeleteImg = (event) => {const { dispatch, uploadUrl, handleFetchUrl } = this.props;handleFetchUrl('');if (event) {//函数删除的回调this.props.onHandleDelete && this.props.onHandleDelete();event.stopPropagation();}};render() {/*** @description:* @param {String} iconText 按钮文字* @param {Object} style 样式* @param {String} value 内容* @param {String} fileType 文件类型  img/video* @param {String} backgroundImg 背景图,如果是video,缩略图中显示背景图,弹窗大图中显示video* @param {String} showDelete 是否显示删除按钮,showDelete=delete 不显示* @param {Number} size 图片大小单位M,默认8*/const {iconText,style,value,fileType,backgroundImg,disabled,infoText,showDelete,size,errorSizeMsg,errorTypeMsg,} = this.props;console.log(iconText)const { visible, shadow, loading } = this.state;return (<div className={styles.ContentBox}><Spin spinning={loading}><UploadlistType="picture-card"showUploadList={false}customRequest={this.handleUpload}beforeUpload={this.beforeUpload}disabled={disabled}>{value ? (<divclassName={styles.imgContent}style={{width: 150,height: 150,display: 'flex',flexDirection: 'column',alignItems: 'center',justifyContent: 'center',...style,}}onMouseOver={() => this.setShadow(true)}onMouseLeave={() => this.setShadow(false)}>{(fileType === 'img' || !fileType) && (<imgalt={iconText}src={value}style={{maxWidth: (style && style.width && style.width) || 150,maxHeight: (style && style.height && style.height) || 150,}}/>)}{fileType === 'video' && (<imgalt={iconText}src={backgroundImg}style={{maxWidth: (style && style.width && style.width) || 150,maxHeight: (style && style.height && style.height) || 150,}}/>)}{shadow && (<div className={styles.imgShadow}><divclassName={styles.shadowDiv}onClick={(event) => {event.stopPropagation();}}/><div className={styles.shadowDiv}><Tooltip title="放大"><Icontype="zoom-in"onClick={(event) => {this.handleSetVisible(true, event);}}/></Tooltip><Divider type="vertical" style={{ width: 2 }} /><Tooltip title="替换"><Icon type="upload" /></Tooltip>{!disabled && showDelete != 'delete' && (<><Divider type="vertical" style={{ width: 2 }} /><Tooltip title="删除"><Icontype="delete"onClick={(event) => {this.handleDeleteImg(event);}}/></Tooltip></>)}</div><divclassName={styles.shadowDiv}onClick={(event) => {event.stopPropagation();}}/></div>)}</div>) : (<divstyle={{width: 150,height: 150,display: 'flex',flexDirection: 'column',alignItems: 'center',justifyContent: 'center',...style,}}><Icon type="plus" /><div className="ant-upload-text" 
style={{ marginTop: 14, whiteSpace: 'normal' }}>{iconText || '上传图片'}</div></div>)}</Upload><div style={{ color: '#666', 
fontSize: '12px', lineHeight: '12px', textAlign: 'center' }}>{infoText ? infoText : ''}</div><ModalmaskClosable={false}maskClosable={false}visible={visible}footer={null}onCancel={() => this.handleSetVisible(false)}>{(fileType === 'img' || !fileType) && (<imgalt={iconText}style={{width: 476,}}src={value}/>)}{fileType === 'video' && (<videoalt={iconText}style={{width: 476,}}src={value}controls/>)}</Modal></Spin></div>);}
}

 备注

fileUpload为接口调用

export function fileUpload(params) {

  return request({ url: `xxxxxxxx`, method: 'form', params });

}

 BaseUploadImage组件

 * @Description: 公共上传图片* @param {Array} type 图片格式。默认类型为png,jpeg* @param {Number} size 图片限制大小 默认大小为8M* @param {String} errorTypeMsg 图片格式错误文字提示* @param {String} errorTypeMsg 图片大小错误文字提示* @param {Function} handleFetchUrl 选中图片后回调函数,目前只在单选中有,适配旧版本* @param {String} uploadUrl 上传图片请求的url,默认为admin/fileUpload* @param {String} iconText 按钮文字* @param {Object} style 样式* @param {String} value 当前图片地址* @param {Boolean} multiple 是否多选*  * *@param {String} showDelete 是否显示删除按钮,showDelete=0 不显示* * @param {Number} size 图片大小单位M*/
import React, { Component } from 'react';
import { Tooltip, Upload, Icon, message, Modal, Divider } from 'antd';
import styles from './index.less';
import UploadImage from './upload.js';export default class BaseUploadImage extends Component {constructor(props) {super(props);this.state = {imgList: (props.multiple ? props.value : [props.value]) || [''],};}componentWillMount() {this.props.onRef && this.props.onRef(this);window.up = this;}/*** @description: 父组件传入的默认值发生改变时,更改图片的默认显示* @param {*} nextProps 最新的props*/componentWillReceiveProps(nextProps) {const {props: { multiple, maxCount = 9 },} = this;const { value } = nextProps;let imgList;if (nextProps.value !== this.props.value) {if (multiple) {imgList = value;if (value && value.length && value.length < maxCount) {imgList.push('');}} else {imgList = [value];}this.setState({imgList: imgList || [''],});}}/*** @description: 上传图片回调* @param {*} val 上传图片后服务器返回的值* @param {*} index 上传的图片index,多选时用*/handleSetImg = (val, index) => {const { multiple, maxCount = 9 } = this.props;const { imgList } = this.state;if (multiple) {if (!val && imgList.length > 0) {if (imgList.length === maxCount) {imgList.push('');}imgList.splice(index, 1);} else {imgList[index] = val;if (maxCount > imgList.length) {imgList.push('');}}this.setState({imgList,});} else {this.setState({ imgList: [val] });}};handleChange = () => {this.props.handleDeleteImg && this.props.handleDeleteImg();};handleUploadImg = () => {console.log(22222);this.props.handleUpload && this.props.handleUpload();};/*** @description: 获取当前上传成功的图片* @return {*} 当前上传成功的图片*/getActiveImg = () => {const { multiple, maxCount = 9 } = this.props;const { imgList } = this.state;if (multiple) {//因为多选的时候,如果没有上传到最大可上传限度,会多出一条数据,所以如果上传数量小于maxCount,需要删掉最尾的一条数据if (maxCount === imgList.length && imgList[imgList.length - 1]) {return imgList;} else {return imgList.slice(0, imgList.length - 1);}} else {return imgList && imgList[0];}};render() {/*** @description:* @param {Boolean} multiple 是否多选* @param {Number} maxCount 多选时,最多可以上传几个*/const {multiple,maxCount = 9,iconText,style,fileType,backgroundImg,disabled,infoText,dispatch,showDelete,size,errorSizeMsg,errorTypeMsg,} = this.props;const { imgList } = this.state;return (<div className={styles.ContentBox}>{multiple && (imgList && typeof imgList === 'object' && imgList.length > 0) ? (imgList.map((item, index) => {console.log(item);return (maxCount >= index && (<UploadImageonHandleDelete={() => {this.handleChange();}}handleUploadImage={() => {this.handleUploadImg();}}iconText={iconText}style={style}fileType={fileType}backgroundImg={backgroundImg}disabled={disabled}infoText={infoText}key={index}dispatch={dispatch}value={item}showDelete={showDelete}size={size}errorTypeMsg={errorTypeMsg}errorSizeMsg={errorSizeMsg}handleFetchUrl={this.props.handleFetchUrl || ((val) => this.handleSetImg(val, index))}/>));})) : (<UploadImageonHandleDelete={() => {this.handleChange();}}handleUploadImage={() => {this.handleUploadImg();}}iconText={iconText}style={style}fileType={fileType}backgroundImg={backgroundImg}disabled={disabled}infoText={infoText}dispatch={dispatch}value={imgList[0]}showDelete={showDelete}size={size}errorTypeMsg={errorTypeMsg}errorSizeMsg={errorSizeMsg}handleFetchUrl={this.props.handleFetchUrl || ((val) => this.handleSetImg(val))}/>)}</div>);}
}

index.less

样式文件

.ContentBox {display: inline-block;.imgContent {padding: 8px;position: relative;display: flex;justify-content: center;align-items: center;.imgShadow {width: 100%;height: 100%;position: absolute;background: rgba(0,0,0,0.5);.shadowDiv {height: 33.3333333%;display:flex;justify-content: space-around;color: #fff;align-items: center;font-size: 18px;padding: 0 10px;}}}
}

父组件引用

    <Form.Item label="上传图片"><BaseUploadImageonRef={(ref) => {this.upload = ref;}}value={this.state.themeImgPath}multiple/></Form.Item>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/405442.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机面试的时候写过的代码,程序员悲催瞬间:来之不易的美团面试,我尽然挂了(还原真实场景)...

一面1、自我介绍答&#xff1a;自我介绍是面试中唯一的自己主动介绍自己的环节&#xff0c;一定要好好把握好&#xff0c;你数据结构学的号可以手撕一个红黑树你就说我数据结构掌握地很好&#xff0c;反正就是要把自己的优势凸显出来&#xff0c;比如自己对于java的知识较熟悉&…

华为IoT平台NB编解码插件开发详细教程【下篇】

上篇文章介绍了编解码开发汇总的环境搭建、Profile说明和插件编写&#xff0c;本篇教程就插件打包、插件质检和插件签名详解。 目录 四、插件打包 五、插件质检 六、插件签名 七、附件 四、插件打包 1、新建package文件&#xff0c;包含一个“preload”子文件夹&#xff…

【PostGIS】PostgreSQL15+对应PostGIS安装教程及空间数据可视化

一、PostgreSQL15与对应PostGIS安装 PostgreSQL15安装&#xff1a;下载地址PostGIS安装&#xff1a;下载地址&#xff08;选择倒数第二个&#xff09; 1、PostgreSQL安装 下载安装包&#xff1b;开始安装&#xff0c;这里使用默认安装&#xff0c;一直next直到安装完成&…

React实现图片自适应

数据格式 [1xxxx,2xxxx,3xxxx,4xxxx,5xxxx,6xxxx,7xxxx,8,xxxx,9xxxx] 运行效果 代码部分 <divgutter{24}style{{width: 100%,display: flex,justifyContent: space-between,flexWrap: wrap ,}}>{item.imgList &&item.imgList.map((itemList, index) > (<…

上交大计算机复试机师难不难,本科复旦,考研上海交大复试第一,我感觉难度并不大...

我本人去年考研上海交大凯原法学院法学硕士&#xff0c;初试370分&#xff0c;排名第四。复试182分&#xff0c;排名第一。本科复旦&#xff0c;有过转专业经历因此法学院课程只学了3年&#xff0c;比较匆忙&#xff0c;基础不算好。2020年国家法律职业资格考试和考研同时备考&…

前端问题记录1:debounce is not a function

目录 项目场景&#xff1a; 问题描述&#xff1a; 原因分析&#xff1a; 解决方案&#xff1a; 项目场景&#xff1a; 问题描述&#xff1a; 原因分析&#xff1a; 变量重名 解决方案&#xff1a; 变量重名 关注我 一起进入前端学习群 谢谢

Linux Shell 通配符、元字符、转义符使用实例介绍

From: http://www.cnblogs.com/chengmo/archive/2010/10/17/1853344.html 说到shell通配符&#xff08;wildcard&#xff09;&#xff0c;大家在使用时候会经常用到。下面是一个实例&#xff1a; ?1?1234[chengmolocalhost ~/shell]$ lsa.txt b.txt c.old#2?1234[chengmo…

ant design model实现图片预览

代码部分 <divgutter{16}style{{width: 100%,display: flex,justifyContent: space-between,flexWrap: wrap ,}}>{detailMsg.imgList &&detailMsg.imgList.map((item, index) > (<div style{{ width: 30% }} key{index} onClick{() > this.handleClick(…

VMware Workstation Pro 无法在Windows 上运行的 解决办法

一、问题描述 国庆期间window10来了一次更新&#xff0c;导致VMware Workstation 无法在windows上运行&#xff0c;我的虚拟机版本是VMware Pro14。有两种方法解决该问题&#xff0c;第一种是直接卸载新安装的windows安装包&#xff0c;然后重启。第二种方式是升级VMware到最新…

机器学习之深度学习

本文基于台大机器学习技法系列课程进行的笔记总结。 一、主要内容 topic 1 深度神经网络结构 从类神经网络结构中我们已经发现了神经网络中的每一层实际上都是对前一层进行的特征转换&#xff0c;也就是特征抽取。一般的隐藏层&#xff08;hidden layer&#xff09;较少的类神…

FlexViewer2.3中拉帘Widget下载

http://www.giser.net/?p280 由于最新的ArcGIS API for flex2.x使用了Flex SDK4&#xff0c;因此造成了对之前ArcGIS API for flex1.x制 作的拉帘Widget无法使用&#xff0c;因此重新制作了拉帘工具供大家使用。 下载地址&#xff1a; Swipe 使用方法&#xff1a;将下载后的sw…

五种I/O 模式——阻塞(默认IO模式),非阻塞(常用语管道),I/O多路复用(IO多路复用的应用场景),信号I/O,异步I/O

From: http://blog.163.com/xychenbaihuyeah/blog/static/13222965520112163171778/ 五种I/O 模式&#xff1a; 【1】 阻塞 I/O (Linux下的I/O操作默认是阻塞I/O&#xff0c;即open和socket创建的I/O都是阻塞I/O) 【2】 非阻塞 I/O (可以通过f…

Linux tm time_t timeval timespec以及与时间相关函数用法

一、时间类型 linux中编程通常需要用到时间变量&#xff0c;和相关的时间操作函数。常用的时间类型有&#xff1a; time_t 、struct timeval、struct timespec、struct tm。 在用到相关的类型和函数时&#xff0c;需要加上头文件&#xff1a;#include <time.h> …

C语言编程对缓冲区的理解

解析C语言编程对缓冲区的理解 转载自&#xff1a;http://soft.chinabyte.com/database/47/12481547.shtml 下面介绍缓冲区的知识。 一、什么是缓冲区 缓冲区又称为缓存&#xff0c;它是内存空间的一部分。也就是说&#xff0c;在内存空间中预留了一定的存储空间&#xff0c;这些…

ftp文档服务器设置,ftp服务器基本设置

ftp服务器基本设置 内容精选换一换在迁移Agent中输入华为云账号AK/SK以后&#xff0c;AK/SK校验失败。Windows系统提示用户&#xff1a;"AK/SK authentication failed. Ensure that the system time is consistent with the standard time and the AK and SK are corre服务…

树莓派移植SX1278 LoRa通信--使用wiringPiSPI移植SPI通信接口

一、SPI接口 树莓派3B上的SPI接口如下所示&#xff0c;有两组SPI&#xff0c;分别由CE0和CE1来进行选择。 首先查看树莓派的SPI是否启用&#xff0c;在/dev查看是否有spidev0.0和spidev0.1 如果不存在spi设备号&#xff0c;需要在raspi-config中启用&#xff0c;在命令行输入&…

饥荒专用服务器全图显示代码,饥荒开全图代码

用记事本打开游戏目录\data\DLC0001\scripts\prefabs\player_common.lua文件&#xff0c;在inst:AddComponent("resurrectable")下一行插inst:AddComponent("resurrectable")下一行插入以下内容&#xff1a;  TheInput:AddKeyUpHandler(KEY_1&#xff0c…

树莓派移植SX1278 LoRa通信--使用wiringPi 移植GPIO中断

一、SX1278 数字接口状态映射 从官方文档可知sx1278的数字接口状态映射明细&#xff0c;移植的代码中主要用查询的方式来判断在连续模式下是否接收和发送完成&#xff0c;因此只需要用到DIO0。如果要用到CAD&#xff0c;则需要DIO1管脚。 发送时&#xff1a;DioMapping1寄存器…

VMware View 与 Citrix Xendesktop 管理大比拼

一篇写得非常不错的博文&#xff0c;从管理角度来对比虚拟桌面产品的差异&#xff0c;而这一点往往被代理商和用户忽略&#xff0c;值得花时间看看。 大部分用户决定使用桌面虚拟化的最大原因是简化管理。我深刻的记得2006年在X福记用户那推补丁管理软件时&#xff0c;结…

matlab 画箱线图boxplot简单用法

代码示例&#xff1a; data1rand(5,1);%列向量 data2rand(5,1);%列向量 data3rand(5,1);%列向量 data[data1,data2,data3]; boxplot(data,Labels,{data1,data2,data3}); 更多请参考&#xff1a; matlab官网文档&#xff1a;https://www.mathworks.com/help/stats/boxplot.htm…