代码详情 (存在的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;