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>

.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM