react+antd实现图片上传并且剪裁(请参照最新文章,此案例有bug)

代码详情 (存在的bug:只有第一次上传剪裁是正确的,在不刷新页面的情况下再次进行剪裁会出现错误,目前没有找到解决办法.)

解决办法:点击上传按钮完成上传之后,按钮变为不能点击的状态,阻止bug的发生.用户再次刷新可进行上传剪裁.

import React, { Component } from 'react';
import { Button, Switch, Upload, Input, message,Modal,Icon } from 'antd';
import styles from './AppletsPreview.less';
import config from '../../config.js';
import { getUid } from '../../utils/auth';
import request from '../../utils/request';
import Cropper from 'react-cropper'; // "cropper": "^4.1.0"  "react-cropper": "^1.3.0",
import '../../../node_modules/cropperjs/dist/cropper.css';  //必须要引入 要不然没有剪裁的效果
const { TextArea } = Input;
import $ from "jquery";
const UID = getUid();
//将图片转为base64位
function getBase64(img, callback) {
    const reader = new FileReader();
    reader.addEventListener('load', () => callback(reader.result));
    reader.readAsDataURL(img);
    // console.log(reader.readAsDataURL(img))
}
function blobToFile(theBlob){
    theBlob.lastModifiedDate = new Date();
    // theBlob.name = fileName;
    return theBlob;
}
// 获取图片尺寸  对图片大小进行处理
function getSize(size){
    var num=parseInt(size);
    if(num<=300){//先要求图片的大小小于300之间
        return num;
    }
    return getSize(num/2);
}
// 圆形裁剪
function getRoundedCanvas(sourceCanvas) {
    var canvas = document.createElement('canvas');
    var context = canvas.getContext('2d');
    var width = sourceCanvas.width;
    var height = sourceCanvas.height;
      width=getSize(width);
      height=width;
    canvas.width = width;
    canvas.height = height;
    context.beginPath();
    context.arc(width/2, height/2, Math.min(width, height)/2, 0, 2 * Math.PI);
    context.strokeStyle = 'rgba(0,0,0,0)';
    context.stroke();
    context.clip();
    context.drawImage(sourceCanvas, 0, 0, width, height);
      
    return canvas;
}

// 裁剪图片插件
class CropperDemo extends Component {
    _crop(){
    }
  
    handleOk = () => {
        //将裁剪的图片转成blob对象
        // this.refs.cropper.getRoundedCanvas().toBlob((blob)=> {  //剪裁形状是方形的
        getRoundedCanvas(this.refs.cropper.getCroppedCanvas()).toBlob((blob) => {  //剪裁形状是圆形的(参考了cropper.js的api)
        // this.refs.cropper.getCroppedCanvas().toBlob((blob) => {
            this.props.onOk(blob);
        },"image/png");
    }
   
    render() {
      const { src } = this.props;
      return (
        <div className="cropper-wrap">
          <Cropper
            ref='cropper'
            src={src}
            style={{height: 400, width: '100%'}}  //整个剪切组件的长宽
            aspectRatio={12 / 12}
            guides={false}
            crop={this._crop.bind(this)} 
            zoomable={false} //不可以对图片进行缩放
            viewMode={1}
            minCropBoxHeight={160}  //设置剪裁框可缩小的最小高度
            minCropBoxWidth={160}  //设置剪裁框可缩小的最小宽度
          />
          <Button style={{marginTop:10}} onClick={this.handleOk}>确认</Button>
        </div>
      );
    }
}

class AppletsPreview extends Component {
    constructor(props) {
        super(props);
        this.state = {
            uploadImg: props.liveInfo.applet_logo,
            cropVisible:false,//裁剪弹窗
            cropSrc:'',
            loading: true,
            path:'',//路径
        };
    }
    componentDidMount(){
        setTimeout(()=>{
            this.getLiveInfos()
        },100)
    }
    componentWillReceiveProps(props) {
        if (props && props.liveLoading == false) {
            if(this.state.uploadImg && this.state.uploadImg.indexOf('/Public/')==-1){
                //找不到
                this.setState({
                    uploadImg: 'http://console.nuoyun.tv/Public/'+props.liveInfo.applet_logo
                })
            }else if(this.state.uploadImg && this.state.uploadImg.indexOf('/Public/')!==-1){
                this.setState({
                    uploadImg: props.liveInfo.applet_logo
                })
            }
            
        }
    }
    handleOk = (dataUrl) => {
        this.setState({
          cropVisible: false
        });
        this.blob= dataUrl;   //  this.blob既是裁剪后的图片,也可以作为裁剪结束的标志
        getBase64(dataUrl, uploadImg => this.setState({
            uploadImg
        }));
    }
    handleCropCancel = () =>{
        this.setState({
            cropVisible: false
        });
    }
    beforeUpload=(file)=> {
        const isJPG = file.type === 'image/jpeg';
        const isPNG = file.type === 'image/png';
        const isGIF = file.type === 'image/gif';
        const isLt2M = file.size / 1024 / 1024 < 2;
        if (!isJPG && !isPNG && !isGIF) {
            message.error('只能上传jpg|png|gif');
            return false;
        }else{
            if (!isLt2M) {
                message.error('图片尺寸必须小于 2MB!');
                return false;
            }
        }
        let reader = new FileReader();
        reader.readAsDataURL(file); 
        let _this = this;
        reader.onload = (e) => {
            $('.cropper-view-box img').attr('src',e.target.result)
            $('.cropper-wrap-box .cropper-canvas img.cropper-hide').attr('src',e.target.result)
            _this.setState({
                cropSrc: e.target.result,
                cropVisible: true,
            })
        }
        return new Promise((resolve, reject) => {
            let index = setInterval(() => {
                if(this.blob){  // 监听裁剪是否完成
                    window.clearInterval(index);
                    this.blob.uid = file.uid;   // 需要给裁剪后的blob对象设置uid,否则会报错!!!
                    resolve(this.blob);   // 执行后续的上传操作
                }
            },100);
        });
    }
    //上传小程序logo图
    UploadAppletsPic = (info) => {
        this.setState({
            loading:false
        })
        let data = {
            base64_image_content:this.state.uploadImg
        }
        if (info.file.status === 'done') {
            
            // if(this.state.uploadImg.indexOf('/Public/')==-1 && this.state.uploadImg.indexOf('data:image/png')!=-1){
                //找不到
                request(`保存图片接口地址(上传的数据是base64位)`, {
                    method: 'POST',
                    // headers: config.headers,
                    headers: {'Content-Type':'application/json'},
                    credentials: "include",
                    body: config.parseJson(data)
                }).then((res) => {
                    this.setState({
                        uploadImg:res.data.src, //图片完整地址
                        path:res.data.path //图片部分路径
                    })
                });
            
        }
    }

    saveGuideConfig = () => {
        const { saveAppletsPreviewConfig, liveInfo,getLiveInfo } = this.props;
        let uploadImg = this.state.uploadImg;
        var obj = {
            id: liveInfo.id,
            applet_logo: this.state.path
        }
        saveAppletsPreviewConfig(obj);
        setTimeout(()=>{
            if(liveInfo&&liveInfo.id){
                getLiveInfo(liveInfo.id)
            }
        },500)
    }

    render() {
        const {liveInfo} = this.props;
        const {uploadImg,isUltimate,isBlock} = this.state;
        return (
            <div className="AppletsPreview">
              <div><div className="configLeft">
                        <div className="title">小程序图标</div>
                        <div className="upload-container">
                        {/* 默认小程序logo图 */}
                            <img src={uploadImg?uploadImg:require('../../assets/applet_logo.png')} className="qrcode"/>
                            {/* 上传小程序logo图 */}
                            <Upload
                                name="guidepic"
                                onChange={this.UploadAppletsPic}
                                action="/api/Wechat/Applet/base64Save"
                                headers={config.headerAuth}
                                showUploadList={false}
                                beforeUpload={this.beforeUpload}
                                >
                                <Button disabled={this.state.loading?false:true}>{this.state.loading?'点击上传':'已上传'}</Button>
                                <li style={{listStyle: "disc",color: "rgb(153, 153, 153)", fontSize:12,marginTop:15}} onClick={(e)=>{e.stopPropagation()}}>刷新页面后可再次点击上传</li>
                                {/* <ul style={{listStyle: "disc", margin: "35px 0px 20px 15px", color: "rgb(153, 153, 153)", fontSize:12,lineHeight:'22px',paddingLeft:10}}>
                                    <li></li>
                                </ul> */}
                            </Upload>
                            {/* 弹框代码 */}
                            <Modal visible={this.state.cropVisible} footer={null} onCancel={this.handleCropCancel} className="crop-modal">
                                <CropperDemo src={this.state.cropSrc} onOk={this.handleOk} />
                            </Modal>
                        </div>
                        <ul style={{listStyle: "disc", margin: "35px 0px 20px 15px", color: "rgb(153, 153, 153)", fontSize:12,lineHeight:'22px',paddingLeft:10}}>
                            <li>图片大小 2M 以内</li>
                            <li>建议尺寸:136×136</li>
                            <li>支持 PNG、JPG、JPEG</li>
                        </ul>
                        <Button style={{marginTop:60, display:"block", width: 150,paddingLeft:10}} type="primary" onClick={this.saveGuideConfig}>保存配置</Button>
                    </div>
                    <div className='configRight'>
                        <img src={uploadImg?uploadImg:require('../../assets/applet_logo.png')} className="qrcode-preview"/>
                    </div>
                    </div>
            </div>
        );
    }
}

export default AppletsPreview;

参考链接:https://www.codeleading.com/article/1734784204/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值