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