当前位置: 首页 > 工具软件 > react-cursor > 使用案例 >

react+antd+react-cropper裁剪图片组件封装

微生昌胤
2023-12-01

tip:之前写了一个裁剪 但是有bug(参考之前的文章) 现在又遇见这个功能 终究是躲不过了 现已解决之前出现的bug 整理代码并封装成了组件 供大家参考使用 避免踩雷
notice:react版本:15.4.0(博主使用版本,版本的不同,代码可稍作修改)

1.Cropper.js
import React, { Component } from 'react'
import { Button, message,Icon} from 'antd';
import Cropper from 'react-cropper' // 引入Cropper
import 'cropperjs/dist/cropper.css' // 引入Cropper对应的css
import './Cropper.less';

export default class ClassCropperModal extends Component {
  constructor(props) {
    super(props)
    this.state = {
      src: null
    }
  }

  componentDidMount() {
    const fileReader = new FileReader()
    fileReader.onload = e => {
      const dataURL = e.target.result
      this.setState({ src: dataURL })
    }

    fileReader.readAsDataURL(this.props.uploadedImageFile)
  }

  handleSubmit = () => {
    if (!this.state.submitting) {
      // let url = `/homepage_images` // 你要上传的url
      // 拿到文件名
      // let filename = this.props.uploadedImageFile.name

      console.log('正在上传图片')
      // TODO: 这里可以尝试修改上传图片的尺寸
      this.cropper.getCroppedCanvas().toBlob(async blob => {
        // // 创造提交表单数据对象
        // const formData = new FormData()
        // // 添加要上传的文件
        // formData.append('file', blob, filename)
        // 提示开始上传 (因为demo没有后端server, 所以这里代码我注释掉了, 这里是上传到服务器并拿到返回数据的代码)
        // this.setState({submitting: true})
        // 上传图片
        // const resp = await http.post(url, formData)
        // 拿到服务器返回的数据(resp)
        // console.log(resp)
        // 提示上传完毕
        // this.setState({submitting: false})

        //把选中裁切好的的图片传出去
        this.props.onSubmit(blob);

        // 关闭弹窗
        this.props.onClose()
      })
    }
  }

  render() {
    const {option} = this.props;
    return (
      <div className="class-cropper-modal">
        <div className="modal-center">
            <div className="class-cropper-header">
              <p>裁剪</p>
              <Icon type="close" onClick={()=>{this.props.onClose()}}/>
            </div>
            {
              this.state.src ? <div className="modal-panel">
                <div className="cropper-container-container">
                  <div className="cropper-container">
                    <Cropper
                      src={this.state.src}
                      className={option.className}
                      ref={cropper => (this.cropper = cropper)}
                      // Cropper.js options
                      viewMode={option.viewMode}//定义cropper的视图模式,1代表限制裁剪框不超过画布大小
                      zoomable={option.zoomable}//是否允许放大图像,默认为true
                      aspectRatio={option.aspectRatio} // 固定为1:1  可以自己设置比例, 默认情况为自由比例
                      guides={option.guides}//显示在裁剪框上方的虚线   默认为true
                      preview=".cropper-preview"//指定类名为.cropper-preview的div作为预览的窗口
                      minCropBoxHeight={option.minCropBoxHeight}
                      minCropBoxWidth={option.minCropBoxWidth}
                    />
                  </div>
                  {/* 预览 */}
                  {/* <div className="preview-container">
                    <div className="cropper-preview" />
                  </div> */}
                </div>
              </div> : ''
            }
            <div className="submit-button" onClick={this.handleSubmit}>
                <Button type="primary">裁剪</Button>
            </div>
        </div>
        
      </div>
    )
  }
}
2.Cropper.less
.class-cropper-modal {
    position: fixed;
    background-color:rgba(0, 0, 0, 0.45);
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 1;
    .modal-center{
      width: 625px;
      background-color: #ffffff;
      border-radius: 4px;
    }
    .class-cropper-header{
      display: flex;
      justify-content: space-between;
      align-items: center;
      font-size: 16px;
      color: rgba(0, 0, 0, 0.85);
      height: 57px;
      padding: 20px 30px;
      box-sizing: border-box;
      border-bottom: 1px solid #F4F4F4;
      .anticon{
        color: rgba(0, 0, 0, 0.85);
        font-size: 16px;
        cursor: pointer;
      }
    }
    .modal-panel {
      width: 625px;
      height: 595px;
      background: white;
      padding: 20px 62px;
      display: flex;
      flex-direction: column;
      align-items: stretch;
  
      .button-row {
        height: 50px;
        flex-shrink: 0;
        display: flex;
        justify-content: center;
        
      }
    
      .cropper-container-container {
        flex: 1;
        display: flex;
        align-items: stretch;
        justify-content: space-between;
        height: 100%;
  
        .cropper-container {
          flex: 0 0 501px;
          margin-right: 20px;
          .cropper {
            width: 100%;
            height: 100%;
          }
        }
        .preview-container {
          flex: 1;
          display: flex;
          align-items: flex-end;
          .cropper-preview {
            width: 180px;
            height: 180px;
            overflow: hidden;
            border: 1px solid #383838;
          }
        }
      }
    }
    .submit-button {
      display: flex;
      align-items: center;
      justify-content: flex-end;
      padding: 10px 30px;
      height: 100%;
      color: #383838;
      font-size: 14px;
      border-top: 1px solid #F4F4F4;
    }
  }
utils.js
//图片转base64位
export function getBase64(img, callback) {
	const reader = new FileReader();
	reader.readAsDataURL(img);
	return new Promise(function(resolve){
		reader.addEventListener('load', () => callback(resolve(reader.result)));
	})
}
3.使用
import React, { Component } from 'react';
import { Button, Switch, InputNumber, message,Radio,Input,Slider,Icon,Upload,Popover,Spin } from 'antd';
import config from '../../config.js';
import request from '../../utils/request';
import {getBase64} from '../../utils/utils.js';
import CropperImg from '../Cropper/Cropper';
class InviteDefine extends Component {
    constructor(props) {
        super(props);
        this.state = {
            classModalVisible: false,
            classModalFile: null,//上传文件
            classResultImgUrl: null,//剪辑文件后的地址
        };
    }
  beforeUpload=(file)=> {
        let files = [];
            this.setState({
                fileList: [...files]
            })
             return false;
    }
uploadOptionPic(file){
            this.setState({
                    classModalFile:file.file
                },()=>{
                    this.setState({
                        classModalVisible:true
                    })
                })
}
handleGetResultImgUrl = key => blob => {
        //裁剪后的图片
        let strUrl = '';
        getBase64(blob, str => strUrl = str).then((value)=>{
            let data = {
               value
            }
            //把blob转为可访问的url地址
            request(`xxxx/base64Save`, {
                method: 'POST',
                // headers: config.headers,
                headers: {'Content-Type':'application/json'},
                credentials: "include",
                body: config.parseJson(data)
            }).then((res) => {
                //获取到图片链接
        })
  }
}
  render(){
    const {classModalVisible,classModalFile} = this.state;
    const uploadButton = (
            <div className="uploadButton">
                <Icon type={this.state.loading ? 'loading' : 'plus'} />
                <p>添加自定义背景</p>
            </div>
        );
return(
<div>
        <Upload 
                name="goods" 
                listType="picture-card" 
                showUploadList="false" 
                className="picUpload"
                action=""
                beforeUpload={this.beforeUpload}
                onChange={this.uploadOptionPic.bind(this,'add')}
                headers={config.headerAuth}
                showUploadList={false}
                accept=".png,.jpg,.jpeg,.gif"
           >
                {
                       uploadButton
                }
        </Upload>
            {classModalVisible && (
                            <CropperImg
                                uploadedImageFile={classModalFile}
                                onClose={() => {
                                this.setState({ classModalVisible: false,editClassModalVisible:false })
                                }}
                                onSubmit={this.handleGetResultImgUrl}
                                option={{minCropBoxHeight:1334,minCropBoxWidth:750,aspectRatio:1/1.792,zoomable:true,guides:false,viewMode:1,className:'cropper'}}
                                visible={classModalVisible}
                            />
                            )}
    </div>
)
}
 类似资料: