本次做后台管理系统,采用的是 AntD 框架。涉及到图片的上传,用的是AntD的 upload 组件。

我在上一篇文章《AntD框架的upload组件上传图片时使用customRequest方法自定义上传行为》中讲到:AntD 的 upload 组件有很多坑。

今天这篇文章,我们继续来研究 AntD 的 upload 组件的另一个坑。

备注:本文写于2020-06-11,使用的 antd 版本是 3.13.6。

使用 AntD 的 upload 组件做图片的上传,效果演示

因为需要上传多张图片,所以采用的是照片墙的形式。上传成功后的界面如下:

(1)上传中:

(2)上传成功:

(3)图片预览:

代码实现

首先,你需要让后台同学提供好图片上传的接口。上一篇文章中,我们是把接口调用直接写在了 <Upload> 标签的 action 属性当中。但如果你在调接口的时候,动作很复杂(比如根据业务要求,需要调两个接口才能上传图片,或者在调接口时还要做其他的事情),这个 action 方法就无法满足需求。那该怎么做呢?

好在 AntD 的 upload 组件给我们提供了 customRequest这个方法:

关于customRequest 这个方法, AntD 官方并没有给出示例,他们只是在 GitHub 上给出了这样一个简短的介绍:

但这个方法怎么用呢?用的时候,会遇到什么问题呢?AntD 官方没有说。我在网上搜了半天,也没看到比较完整的 Demo。既然如此,那我就自己研究吧。折腾了一天,总算是把 customRequest 的坑踩得差不多了。

啥也不说了,直接上代码。

采用 AntD框架的 upload 组件的 customRequest 方法,自定义上传行为。核心代码如下:

import React, { PureComponent } from 'react';
import { Button, Card, Form, message, Upload, Icon, Modal, Row, Col } from 'antd';
import { connect } from 'dva';
import { queryMyData, submitData } from '../api';
import { uploadImage } from '../../utils/wq.img.upload'; import styles from '../../utils/form.less'; const FormItem = Form.Item; @Form.create()
export default class PicturesWall extends PureComponent {
constructor(props) {
super(props);
const { id } = this.props.match.params;
this.state = {
id,
img: undefined, // 从接口拿到的图片字段
imgList: [], // 展示在 antd图片组件上的数据
previewVisible: false,
previewImage: '',
};
} componentDidMount() {
const { id } = this.state;
id && this.queryData();
} // 调接口,查询已有的数据
queryData() {
const { id } = this.state;
queryMyData({
id,
})
.then(({ ret, data }) => {
if (ret == 0 && data && data.list && data.list.length) {
const item = data.list[0]; const img = data.img;
const imgList = item.img
? [
{
uid: '1', // 注意,这个uid一定不能少,否则展示失败
name: 'hehe.png',
status: 'done',
url: img,
},
]
: []; this.setState({
img,
imgList,
});
} else {
return Promise.reject();
}
})
.catch(() => {
message.error('查询出错,请重试');
});
} handleCancel = () => this.setState({ previewVisible: false }); // 方法:图片预览
handlePreview = (file) => {
console.log('smyhvae handlePreview:' + JSON.stringify(file));
this.setState({
previewImage: file.url || file.thumbUrl,
previewVisible: true,
});
}; // 参考链接:https://www.jianshu.com/p/f356f050b3c9
handleBeforeUpload = (file) => {
console.log('smyhvae handleBeforeUpload file:' + JSON.stringify(file));
console.log('smyhvae handleBeforeUpload file.file:' + JSON.stringify(file.file));
console.log('smyhvae handleBeforeUpload file type:' + JSON.stringify(file.type)); //限制图片 格式、size、分辨率
const isJPG = file.type === 'image/jpeg';
const isJPEG = file.type === 'image/jpeg';
const isGIF = file.type === 'image/gif';
const isPNG = file.type === 'image/png';
const isLt2M = file.size / 1024 / 1024 < 1;
if (!(isJPG || isJPEG || isPNG)) {
Modal.error({
title: '只能上传JPG、JPEG、PNG格式的图片~',
});
} else if (!isLt2M) {
Modal.error({
title: '图片超过1M限制,不允许上传~',
});
}
return (isJPG || isJPEG || isPNG) && isLt2M;
}; // checkImageWH 返回一个promise 检测通过返回resolve 失败返回reject阻止图片上传
checkImageWH(file) {
return new Promise(function (resolve, reject) {
let filereader = new FileReader();
filereader.onload = (e) => {
let src = e.target.result;
const image = new Image();
image.onload = function () {
// 获取图片的宽高
file.width = this.width;
file.height = this.height;
resolve();
};
image.onerror = reject;
image.src = src;
};
filereader.readAsDataURL(file);
});
} // 图片上传
doImgUpload = (options) => {
const { onSuccess, onError, file, onProgress } = options; // start:进度条相关
// 伪装成 handleChange里面的图片上传状态
const imgItem = {
uid: '1', // 注意,这个uid一定不能少,否则上传失败
name: 'hehe.png',
status: 'uploading',
url: '',
percent: 99, // 注意不要写100。100表示上传完成
}; this.setState({
imgList: [imgItem],
}); // 更新 imgList
// end:进度条相关 const reader = new FileReader();
reader.readAsDataURL(file); // 读取图片文件 reader.onload = (file) => {
const params = {
myBase64: file.target.result, // 把 本地图片的base64编码传给后台,调接口,生成图片的url
}; // 上传图片的base64编码,调接口后,返回 imageId
uploadImage(params)
.then((res) => {
console.log('smyhvae doImgUpload:' + JSON.stringify(res));
console.log('smyhvae 图片上传成功:' + res.imageUrl); const imgItem = {
uid: '1', // 注意,这个uid一定不能少,否则上传失败
name: 'hehe.png',
status: 'done',
url: res.imageUrl, // url 是展示在页面上的绝对链接
imgUrl: res.imageUrl, // imgUrl 是存到 db 里的相对链接
// response: '{"status": "success"}',
}; this.setState({
imgList: [imgItem],
}); // 更新 imgList
})
.catch((e) => {
console.log('smyhvae 图片上传失败:' + JSON.stringify(e || ''));
message.error('图片上传失败,请重试');
});
};
}; handleChange = ({ file, fileList }) => {
console.log('smyhvae handleChange file:' + JSON.stringify(file));
console.log('smyhvae handleChange fileList:' + JSON.stringify(fileList)); if (file.status == 'removed') {
this.setState({
imgList: [],
});
}
}; submit = (e) => {
e.preventDefault(); this.props.form.validateFields((err, fieldsValue) => {
if (err) {
return;
} const { id, imgList } = this.state; const tempImgList = imgList.filter((item) => item.status == 'done'); // 筛选出 status = done 的图片
const imgArr = [];
tempImgList.forEach((item) => {
imgArr.push(item.imgUrl);
// imgArr.push(item.url);
}); submitData({
id,
img: imgArr[0] || '', // 1、暂时只传一张图片给后台。如果传多张图片,那么,upload组件需要进一步完善,比较麻烦,以后有需求再优化。2、如果图片字段是选填,那就用空字符串兜底
})
.then((res) => {
if (res.ret == 0) {
message.success(`${id ? '修改' : '新增'}成功,自动跳转中...`); } else if (res.ret == 201 || res.ret == 202 || res.ret == 203 || res.ret == 6) {
return Promise.reject(res.msg);
} else {
return Promise.reject();
}
})
.catch((e) => {
message.error(e || '提交失败,请重试');
});
});
}; render() {
const { id, imgList } = this.state;
console.log('smyhvae render imgList:' + JSON.stringify(imgList));
const { getFieldDecorator } = this.props.form;
const formItemLayout = {
labelCol: { span: 3 },
wrapperCol: { span: 10 },
};
const buttonItemLayout = {
wrapperCol: { span: 10, offset: 3 },
}; const uploadButton = (
<div>
<Icon type="plus" />
<div className="ant-upload-text">Upload</div>
</div>
); return (
<Card title={id ? '修改信息' : '新增信息'}>
<Form onSubmit={this.submit} layout="horizontal"> {/* 新建产业带图片、编辑产业带图片 */}
<FormItem label="图片" {...formItemLayout}>
{getFieldDecorator('img', {
rules: [{ required: false, message: '请上传图片' }],
})(
<Upload
action="2"
customRequest={this.doImgUpload}
listType="picture-card"
fileList={imgList}
onPreview={this.handlePreview}
beforeUpload={this.handleBeforeUpload}
onChange={this.handleChange}
>
{imgList.length >= 1 ? null : uploadButton}
</Upload>
)}
</FormItem>
<Row>
<Col span={3} />
<Col span={18} className={styles.graytext}>
注:图片支持JPG、JPEG、PNG格式,小于1M,最多上传1张
</Col>
</Row> <FormItem {...buttonItemLayout}>
<Button type="primary" htmlType="submit">
提交
</Button>
</FormItem>
</Form> {/* 图片点开预览 */}
<Modal visible={this.state.previewVisible} footer={null} onCancel={this.handleCancel}>
<img alt="example" style={{ width: '100%' }} src={this.state.previewImage} />
</Modal>
</Card>
);
}
}

AntD框架的upload组件上传图片时使用customRequest方法自定义上传行为的更多相关文章

  1. 前端AntD框架的upload组件上传图片时遇到的一些坑

    前言 本次做后台管理系统,采用的是 AntD 框架.涉及到图片的上传,用的是AntD的 upload 组件. 前端做文件上传这个功能,是很有技术难度的.既然框架给我们提供好了,那就直接用呗.结果用的时 ...

  2. antdv的Upload组件实现前端压缩图片并自定义上传功能

    Ant Design of Vue的Upload组件有几个重要的api属性: beforeUpload: 上传文件之前的钩子函数,支持返回一个Promise对象. customRequest: 覆盖组 ...

  3. iview中upload组件上传图片,跨域

    前提:先前开发了一个A项目,A项目中有一套上传图片的接口,现在开发B项目. B项目开发中用iview中的upload组件上传图片,用到了A项目中上传接口,爬坑经历 1.涉及到了跨域解决:后台配置一下文 ...

  4. vue问题三:element ui的upload组件上传图片成功和移除事件

    element ui的upload组件上传图片成功和移除事件: 登录后获取到后台传的token存到中: sessionStorage.setItem("token",data.ob ...

  5. UI组件--element-ui--Upload多组件自定义上传

    需求: 提交详细信息的表单, 并上传对应图片(如下图), 后台接口要求表单数据和图片需要一次上传完成.. 分析: 实际上, 每个element-ui Upload组件都应发送一次请求, 很明显不符合我 ...

  6. TP框架配合jquery进行3种方式的多图片上传

    用的TP5.1框架+jquery 一 使用form表单方式进行多图片上传 html代码: <form action="../admin/admin/cs" enctype=& ...

  7. html上传图片后,在页面显示上传的图片

    html上传图片后,在页面显示上传的图片 1.html <form class="container" enctype="multipart/form-data&q ...

  8. React antd如何实现<Upload>组件上传附件再次上传已清除附件缓存问题。

    最近在公司做React+antd的项目,遇到一个上传组件的问题,即上传附件成功后,文件展示处仍然还有之前上传附件的缓存信息,需要解决的问题是,要把上一次上传的附件缓存在上传成功或者取消后,可以进行清除 ...

  9. Element upload组件上传图片与回显图片

    场景:新增商品时需要添加商品主图,新增成功之后可编辑 上传图片: <el-form-item label="专区logo:" style="height:160px ...

随机推荐

  1. Reflux之Action

    reflux在flux的基础上,去掉了dispatcher. 在Reflux中,每一个Action本身就是一个Publisher(消息发布者),具有消息发布功能:而每一个Store除了作为数据存储之外 ...

  2. 自己用C语言写NXP S32K144 serial bootloader

    了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader) 欢迎咨询或定制bootloader(在线升级程序). NXP S32K144 ...

  3. kubernetes pod的弹性伸缩———基于pod自定义custom metrics(容器的IO带宽)的HPA

    背景 ​ 自Kubernetes 1.11版本起,K8s资源采集指标由Resource Metrics API(Metrics Server 实现)和Custom metrics api(Promet ...

  4. 安卓网络编程学习(1)——java原生网络编程(1)

    写在前面 马上要进行第二轮冲刺,考虑到自己的APP在第一轮冲刺的效果不尽人意,有很多网络方面的小BUG,这里就系统学习一下网络编程,了解来龙去脉,以便更好的对项目进行优化处理. http协议 http ...

  5. python运用 - log信息提取(知识: 遍历 | os )

    运用到的python知识点: excel相关:https://www.cnblogs.com/yaner2018/p/11269873.html 字典: python字典的几种方式: 1)key值遍历 ...

  6. docker启动各种容器命令大全

    安装步骤梳理 搜索镜像 拉取镜像 查看镜像 启动镜像 停止容器 移除容器 安装tomcat docker hub好查找tomcat镜像  docker search tomcat 从docker hu ...

  7. 自定义realm实现授权

    对用户和权限封装 更具用户查询已经拥有的角色 实现类 根据用户查询已经拥有的权限

  8. Js 改变时间格式输出格式

    朋友看到的方法,非js原生的 自己封装到 function date2str(x,y) { var z={y:x.getFullYear(),M:x.getMonth()+1,d:x.getDate( ...

  9. PIC单片机的i2c的程序

    #include<pic.h>#define uchar unsigned char#define uint unsigned int#define add 0xaa__CONFIG(0x ...

  10. 飞机调度 Now or Later? LA 3211 (2-SAT问题)

    洛谷题目传送门 题目描述 有n架飞机需要着陆.每架飞机都可以选择“早着陆”和“晚着陆”两种方式之一,且必须选择一种.第i架飞机的早着陆时间为Ei,晚着陆时间为Li,不得在其他时间着陆.你的任务是为这些 ...