目录
需求实现
实现效果
代码封装
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>