最近公司项目在做一个求职工具类的小程序,小程序端有企业Logo的显示,为了保证图片在小程序端的展示效果,所以要求在后台管理系统进行企业Logo上传时需要限定上传的图片尺寸和比例。
为了减少管理人员的录入成本,需要在Logo上传前进行裁剪操作,保证上传进来的图片都是规则的正方形。此处用到了react-cropper组件,本文主要介绍了react-cropper组件在Ant Design Pro项目中的应用。
为了解决各位看官的时间,先来看最终实现的效果,如果能够帮到你,再往下看~
- 点击“选择图片”按钮,弹出窗口,选择文件;
- 图片选择成功后直接打开Modal,并将选择的图像绑定在Modal上(熊猫本熊镇楼);
- 裁剪之后点击“确认上传”,上传成功后,关闭Modal,将图片绑定在表单页面的展示框中,齐活~
流程就是这么个流程,接下来开撸~ 首先,考虑到后期可能还会在其他位置使用到该组件,并且为了保持原页面的代码整洁,所以考虑将该组件进行二次封装。
国际惯例的第一步:先安装react-cropper依赖。 如果安装之后有问题引入样式有问题,将node_modules目录删除之后重新安装即可。
npm install react-cropper
如果需要进行图片压缩,再安装lrz组件:
npm install lrz
由于我们的项目是基于Ant Design Pro的,所以直接在src目录下的components目录下新建一个全局组件,命名为ImgCropper;
然后,引入组件,如下图,准备工作完成(此处不再赘述,相信你找到这篇文章时已经做好了这些)
先看render结构
render() {
// 考虑靠组件复用,裁剪Modal的标题作为属性从组件外部传递进来
const { title } = this.props;
/**
* srcCropper:cropper组件内部图片的url
* visible:裁剪Modal的显示属性
* confirmLoading:图片上传过程中Modal的Loading效果
* */
const { srcCropper, visible, confirmLoading } = this.state;
return (
<div>
<Upload beforeUpload={this.beforeUpload} showUploadList={false}>
<Button>
<Icon type="upload" /> 选择图片
</Button>
</Upload>
<Modal
title={title}
visible={visible}
onOk={this.saveImg}
onCancel={this.onCloseModal}
okText="确认上传"
confirmLoading={confirmLoading}
>
<div className={styles.previewHeader}>
{srcCropper ? (
<div className={styles.previewOutter}>
<div className={`${styles.uploadCrop} previewContainer`} />
<div className={`${styles.uploadCropcir} previewContainer`} />
</div>
) : (
''
)}
</div>
{srcCropper ? (
<div className={styles.prevBox}>
<div>
<Cropper
ref="cropper"
style={{ height: 400, width: '100%' }}
// 预览图的容器
preview=".previewContainer"
guides
// 固定图片裁剪比例(正方形)
aspectRatio={1}
// 要裁剪的图片的路径
src={srcCropper}
/>
</div>
</div>
) : (
''
)}
</Modal>
</div>
);
}
此处使用的Antd内置的上传组件Upload(根据从Antd文档,实现先选择文件,再上传)
beforeUpload = file => {
const isLt10M = file.size / 1024 / 1024 < 10;
if (!isLt10M) {
// 添加文件限制
message.error({ content: '文件大小不能超过10M' });
return false;
}
const reader = new FileReader();
reader.readAsDataURL(file); // 开始读取文件
// 因为读取文件需要时间,所以要在回调函数中使用读取的结果
reader.onload = e => {
this.setState({
visible: true,
srcCropper: e.target.result, // cropper的图片路径
});
};
return false;
};
点击Modal的“确认上传”按钮,开始上传:
saveImg = () => {
this.setState({
confirmLoading: true,
});
// 通过refs读取到Cropper实例,并读取到裁剪之后的图片(base64)
const url = this.refs.cropper.getCroppedCanvas().toDataURL();
// 此处使用了lrz组件对裁剪之后的图片进行压缩,lrz的API十分简单,quality是指对压缩图片的品质,一般0.6或者0.7即可
lrz(url, { quality: 0.6 }).then(results => {
const { onSuccess } = this.props;
const fd = new FormData();
// 由于后台接口参数需要一个文件名,所有根据当前时间生成文件名
const imgName = `${new Date().getTime()}.png`;
// 将base64转化成二进制流
fd.append('file', b64toBlob(results.base64), imgName);
// 此处的function参数时候后台规定的,具体需要根据接口情况而定
fd.append('function', 'rims/post/companyLogo/');
// 发送请求
upload(fd).then(res => {
if (res && res.code === 1000) {
// 将返回数据传递到页面上去
onSuccess(res.data);
this.setState({
visible: false,
confirmLoading: false,
});
message.success('上传成功!');
}
});
});
};
上传成功之后,将返回结果传递到组件外部去(用于页面展示)。 具体方法是,通过暴露一个外部的onSuccess属性,该属性是一个函数,并调用该函数传递数据。
上面的代码中,使用到了自己封装的工具方法b64toBlob和upload,具体代码如下:
utils.js
export const b64toBlob = ImageURL => {
const block = ImageURL.split(';');
const contentType = block[0].split(':')[1];
const b64Data = block[1].split(',')[1];
const sliceSize = 512;
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, { type: contentType });
return blob;
};
common.js
import { post } from '@/utils/http';
import prefix from '@/locales/prefix';
const upLoadUrl = `${prefix.RIMS}/file/upload`;
export async function upload(params) {
return post(`${upLoadUrl}`, params);
}
到这里,组件内部的逻辑处理完毕, 接下来便可以在页面中需要的位置调用组件:
组件调用示例:
// 需要传递两个属性:title和onSuccess,
<ImgCropper title="上传企业Logo" onSuccess={this.onImgUpLoadChange} />
onImgUpLoadChange = (data) => {
console.log(data);
// 这里便可以读取到图片上传成功之后的返回值,一般后端接口会返回上传成功之后在服务器存储的url等信息,然后根据业务逻辑进行其他操作即可
}
希望能够帮到你...