前言
大家好 我是歌谣 今天继续给大家带来工作中实战部分的一些代码的封装和认识
需求实现
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}>
<Upload
listType="picture-card"
showUploadList={false}
customRequest={this.handleUpload}
beforeUpload={this.beforeUpload}
disabled={disabled}
>
{value ? (
<div
className={styles.imgContent}
style={{
width: 150,
height: 150,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
...style,
}}
onm ouseOver={() => this.setShadow(true)}
onm ouseLeave={() => this.setShadow(false)}
>
{(fileType === 'img' || !fileType) && (
<img
alt={iconText}
src={value}
style={{
maxWidth: (style && style.width && style.width) || 150,
maxHeight: (style && style.height && style.height) || 150,
}}
/>
)}
{fileType === 'video' && (
<img
alt={iconText}
src={backgroundImg}
style={{
maxWidth: (style && style.width && style.width) || 150,
maxHeight: (style && style.height && style.height) || 150,
}}
/>
)}
{shadow && (
<div className={styles.imgShadow}>
<div
className={styles.shadowDiv}
onClick={(event) => {
event.stopPropagation();
}}
/>
<div className={styles.shadowDiv}>
<Tooltip title="放大">
<Icon
type="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="删除">
<Icon
type="delete"
onClick={(event) => {
this.handleDeleteImg(event);
}}
/>
</Tooltip>
</>
)}
</div>
<div
className={styles.shadowDiv}
onClick={(event) => {
event.stopPropagation();
}}
/>
</div>
)}
</div>
) : (
<div
style={{
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>
<Modal
maskClosable={false}
maskClosable={false}
visible={visible}
footer={null}
onCancel={() => this.handleSetVisible(false)}
>
{(fileType === 'img' || !fileType) && (
<img
alt={iconText}
style={{
width: 476,
}}
src={value}
/>
)}
{fileType === 'video' && (
<video
alt={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 && (
<UploadImage
onHandleDelete={() => {
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))
}
/>
)
);
})
) : (
<UploadImage
onHandleDelete={() => {
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="上传图片">
<BaseUploadImage
onRef={(ref) => {
this.upload = ref;
}}
value={this.state.themeImgPath}
multiple
/>
</Form.Item>
总结
标签:八十七,String,imgList,param,React,&&,props,antDesign,size From: https://blog.51cto.com/u_14476028/6418389我是歌谣 放弃很容易 但是坚持一定很酷 微信公众号关注前端小歌谣带你进入前端巅峰交流群