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,  '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>

.

原文地址:https://www.cnblogs.com/crazycode2/p/12574129.html