react 项目里 实现图片剪裁
1.安装模块
yarn add react-cropper lrz
2.分装组件
src/components/ImgCropper/index.tsx
/**
* 上传logo组件
*/
import * as React from 'react';
import { Upload, Icon, message, Modal, Button } from 'antd';
// 图片剪裁
import Cropper from 'react-cropper';
// 图片压缩
// import lrz from 'lrz';
// base64 转 Blob
import { b64toBlob } from '@utils/b64toBlob';
import { BaseUrl } from '@utils/constants';
import 'cropperjs/dist/cropper.css';
import axios from 'axios';
import './index.less';
const lrz = require('lrz');
interface IProps {
onSuccess?: Function | any;
onChange?: Function | any;
title: string;
aspectRatio?: number;
}
interface IState {
srcCropper: any;
visible: boolean;
confirmLoading: boolean;
}
class ImgCropper extends React.Component<IProps, IState>{
constructor(props: IProps){
super(props);
this.state = {
srcCropper: '',
visible: false,
confirmLoading: false
}
}
beforeUpload = (file: any) => {
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: any) => {
this.setState({
visible: true,
srcCropper: e.target.result, // cropper的图片路径
});
};
return false;
};
saveImg = () => {
this.setState({
confirmLoading: true,
});
// 通过refs读取到Cropper实例,并读取到裁剪之后的图片(base64)
const cropper: any = this.refs.cropper;
const url = cropper.getCroppedCanvas().toDataURL();
// 此处使用了lrz组件对裁剪之后的图片进行压缩,lrz的API十分简单,quality是指对压缩图片的品质,一般0.6或者0.7即可
lrz(url, { quality: 0.6 }).then((results: any) => {
const { onSuccess, onChange } = this.props;
const fd = new FormData();
// 由于后台接口参数需要一个文件名,所有根据当前时间生成文件名
const imgName = `${new Date().getTime()}.png`;
// 将base64转化成二进制流
fd.append('file', b64toBlob(results.base64), imgName);
// 发送请求
axios.post(`${BaseUrl}/tools/saveAvatar`, fd).then((res) => {
const { data={} } = res;
if(data.code === 200){
onSuccess(data.data.file);
onChange && onChange(data.data.file);
message.success(data.message || '上传成功');
}
}).catch((err) => {
message.error('上传失败');
}).finally(() => this.onCloseModal())
});
};
// 取消
onCloseModal = () => {
this.setState({
visible: false,
confirmLoading: false
})
}
render() {
// 考虑靠组件复用,裁剪Modal的标题作为属性从组件外部传递进来
const { title, aspectRatio=1 } = 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="确认上传"
cancelText="取消"
confirmLoading={confirmLoading}
>
{/* <div className="previewHeader">
{srcCropper ? (
<div className="previewOutter">
<div className="uploadCrop previewContainer" />
<div className="uploadCropcir previewContainer" />
</div>
) : (
''
)}
</div> */}
{srcCropper ? (
<Cropper
ref="cropper"
style={{ height: 400, width: '100%' }}
// 预览图的容器
preview=".previewContainer"
guides
// 固定图片裁剪比例(正方形)
aspectRatio={aspectRatio}
// 要裁剪的图片的路径
src={srcCropper}
/>
) : (
''
)}
</Modal>
</div>
);
}
}
export default ImgCropper;
3.页面调用
<Form.Item label="头像">
{getFieldDecorator('avatar', {
rules: [{ required: true, message: '请上传头像' }],
initialValue: detail['avatar'] || undefined
})(<ImgCropper title="上传头像" onSuccess={this.handleSuccess} />)}
{(avatarImg || detail['avatar']) && <img className="avatar-img" src={avatarImg || detail['avatar']} alt="头像" /> || null}
</Form.Item>
.

浙公网安备 33010602011771号