裁剪图片并上传到阿里云的oss服务器上
程序员文章站
2022-04-09 10:29:56
...
在react项目整体利用umijs脚手架搭建,可以进umijs官网跟着步骤一步步来,然后在src目录下新建自己的js组件,样式文件这里没有,想要什么效果,自己可以新建一个空的样式文件进行编写,再测试一下代码即可。其实难点没有,都是别人写好的东东,要学的就是怎么套用,功能是怎么实现的,在实现功能的过程中可以尝试阅读组件的实现方式,学习他人的编码习惯,不断让自己养成编写规范代码的好习惯!!!
先说裁剪
- 下载react-cropper
npm install --save react-cropper
- 需要导入的包
import React, {Component} from 'react';
import {Upload, Icon, Button, Modal} from 'antd'; //利用Ant+Design中的Upload
import Cropper from 'react-cropper'; //在导入之前,确保已经安装了react-cropper
import 'cropperjs/dist/cropper.css'; //cropper样式文件
import './infoManage.scss' //当前组件的样式文件
import userImg from '../../../assets/images/userCenter/head-img.png' //我的页面中需要用到的图片资源
- render部分
render() {
const imageUrl = this.state.imageUrl; //涉及到的state中的初始化变量在第4点中有定义
return (
<div className="user-img">
<div className="img-content-top">
<div className="img-content-left">
<div className="choose-img">
{/*<input type="file" className="myFileUpload" onChange={this.handleFileChange}/>*/}
{
this.state.userImg?
<img className="oldUserImg" src={userImg} alt="用户头像"/>
:
//关于Cropper组件的使用我没有很熟练,只是需要什么效果就添加相应的参数进行配置 [参数解释](https://blog.csdn.net/qq_38048243/article/details/82013533)
<Cropper
src={this.state.srcCropper} //图片路径,即是base64的值,在Upload上传的时候获取到的
ref="cropper"
style={{height: 400}} //react中样式需要写在双大括号中
preview='.cropper-preview' //指定类名为.cropper-preview的div作为预览的窗口
className="company-logo-cropper"
viewMode={1} //定义cropper的视图模式,1代表限制裁剪框不超过画布大小
zoomable={false} //是否允许放大图像,默认为true
aspectRatio={50 / 50} //image的纵横比,即裁剪框的固定宽高比,默认情况下是*比率
guides={true} //显示在裁剪框上方的虚线 默认为true
background={false} //显示容器的网格背景,即是否显示背景的马赛克,默认为true
rotatable={false} //是否允许旋转图像 默认为true
crop={this._crop.bind(this)}
key="1"
>
</Cropper>
}
</div>
{/*<p className="img-request">只支持JPG、PNG、GIF,大小不超过5M</p>*/}
</div>
<div className="img-content-right">
<span className="pre-show">预览</span>
<div className="img-big">
{imageUrl ? <img src={imageUrl} alt="大图" className="upload-big"/> : <i/>}
<span>100*100px</span>
</div>
<div className="img-middle">
{imageUrl ? <img src={imageUrl} alt="中图" className="upload-middle"/> : <i/>}
<span>50*50px</span>
</div>
<div className="img-small">
{imageUrl ? <img src={imageUrl} alt="小图" className="upload-small"/> : <i/>}
<span>30*30px</span>
</div>
</div>
</div>
<div className="img-content-bottom">
//ant design中的Upload组件,详情可查看官网详细代码
<Upload
name="avatar"
listType="picture-card"
className="avatar-uploader myFileUpload"
showUploadList={false}
action="//jsonplaceholder.typicode.com/posts/"
beforeUpload={this.beforeUpload} //上传之前
onChange={this.handleChange}
>
<a className="greenButton">+选择图片</a>
{/*{this.state.imageUrl ? <img src={this.state.imageUrl} alt="avatar" /> : uploadButton}*/}
</Upload>
<button className="sure" onClick={this.submitImg}>确定</button>
<button className="cancel" onClick={this.cancelImg}>取消</button>
<button className="lj-save-img" onClick={this.saveImg}>保存</button>
</div>
</div>
);
}
- 涉及到的方法,因为是react-cropper + ant design一起实现,所以关于上传文件部分的方法直接从ant design官网拷贝就可以了;而跟cropper相关的方法中只需要做相应的state修改就可以实现,关于cropper中参数的解释:
cropper参数解释看过来
function getBase64(img, callback) {
const reader = new FileReader();
reader.addEventListener('load', () => callback(reader.result));
reader.readAsDataURL(img);
}
class UserImg extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
visImg: false,
imageUrl: "",
temporaryUrl: "",
userImg: true,
}
}
//Upload上传之前的函数
beforeUpload = (file) => {
const isLt5M = file.size / 1024 / 1024 < 5;
if (!isLt5M) { //添加文件限制
console.log('文件大小');
return false;
}
const isJPG = file.type === 'image/jpeg';
const isPNG = file.type === 'image/png';
const isGIF = file.type === 'image/gif';
const isIMG = !isJPG || !isPNG || !isGIF;
if (!isIMG) {
console.log('格式不正确');
return false;
}
var reader = new FileReader();
reader.readAsDataURL(file); //开始读取文件
// 因为读取文件需要时间,所以要在回调函数中使用读取的结果
reader.onload = (e) => {
this.setState({
srcCropper: e.target.result, //cropper的图片路径
selectImgName: file.name, //文件名称
selectImgSize: (file.size / 1024 / 1024), //文件大小
selectImgSuffix: file.type.split("/")[1], //文件类型
visImg: true, //打开控制裁剪弹窗的变量,为true即弹窗
userImg:false
})
}
return false;
};
submitImg = () => {
console.log('提交');
};
handleChange = (info) => {
console.log(info.file);
if (info.file.status === 'uploading') {
this.setState({loading: true});
return;
}
if (info.file.status === 'done') {
console.log('执行upload成功');
// Get this url from response in real world.
getBase64(info.file.originFileObj, imageUrl => this.setState({
imageUrl,
srcCropper: imageUrl,
loading: false,
visImg: true,
}));
}
};
// 保存图片
//点击保存的函数,需要在这里进行压缩
saveImg = () => {
const temporaryUrl = this.state.temporaryUrl;
this.setState({
imageUrl: temporaryUrl,
visImg: false,
})
};
_crop() {
// image in dataUrl
const cropperUrl = this.refs.cropper.getCroppedCanvas().toDataURL();
// console.log(this.refs.cropper.getCroppedCanvas().toDataURL());
this.setState({
temporaryUrl: cropperUrl,
// imageUrl: cropperUrl,
})
};
//点击取消按钮的时候“取消修改当前图片,恢复用户原先使用的图片”
cancelImg = ()=>{
this.setState({
userImg:true,
imageUrl:''
})
}
//-----------------------------------------将上边的render方法拷贝在此处--------------------------------------------
}
export default UserImg;
再来上传
【利用Ant Design以及OSS实现图片上传(这里我只简单描述一下单图片上传的步骤)】
- 下载依赖
npm i ali-oss # oss功能封装
npm i moment # 为每一天的上传文件创建目录
- 下载好以后在js组件顶部引入即可
import OSS from 'ali-oss';
import moment from 'moment';
- 在紧跟着import之后将以下代码附上
- 将base64位的图转为blob,
function dataURLtoBlob(dataurl) {
var arr = dataurl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
}
- 个人理解该变量是接收一个跟阿里云oss服务器参数相关的返回值
const client = self => {
const { token } = self.state;
return new OSS({
accessKeyId: token.access_key_id,
accessKeySecret: token.access_key_secret,
region: token.region, //
bucket: token.OSS_BUCKET, //
});
};
- 图片上传最好重新命名,其实很好理解,就是为了防止图片上传后命名冲突的问题
const uploadPath = (path, file) =>
// 上传文件的路径,使用日期命名文件目录
`${moment().format('YYYYMMDD')}/${file.name.split('.')[0]}-${file.uid}.${file.name.split('.')[1]}`;
- 将图片上传到oss服务器
//path对应oss的存储路径位置;
//file对应本地要上传的图片信息,包括名称,路径等
const UploadToOss = (self, path, file) => {
const url = uploadPath(path, file);
return new Promise((resolve, reject) => {
client(self)
.multipartUpload(url, file)
.then(data => {
resolve(data);
})
.catch(error => {
reject(error);
});
});
};
- 将之前写的beforeUpload方法中的reader.onload方法中内容替换成以下代码
// 使用ossupload覆盖默认的上传方法,其中data中有本地file在oss服务器上的存储地址即data.res.requestUrls。
UploadToOss(this, '上传路径oss配置信息', file).then(data => {
this.setState({
//temporaryUrl是我的页面中需要用到的一个state,你可以换成你所要需要的state变量
temporaryUrl: data.res.requestUrls,
srcCropper: e.target.result, //cropper的图片路径
selectImgName: file.name, //文件名称
selectImgSize: (file.size / 1024 / 1024), //文件大小
selectImgSuffix: file.type.split('/')[1], //文件类型
visImg: true, //打开控制裁剪弹窗的变量,为true即弹窗
userImg: false,
});
});
- 如果是裁剪后的图片要上传,可以添加以下方法
//这里方法名随自己定
1.imgUrl参数代表裁剪后的图片,现在这个图片的格式还是base64位格式的
2.因为上传阿里云需要给图片重命名,而重命名需要图片的name以及uid,那么不妨将原图片file传进来,给裁剪后的图片添加需要的属性
upcooper = (imgurl, file) => {
imgurl.name = file.name;
imgurl.uid = file.uid;
var reader = new FileReader();
reader.readAsDataURL(imgurl); //开始读取文件
//因为读取文件需要时间,所以要在回调函数中使用读取的结果
reader.onload = (e) => {
// 使用ossupload覆盖默认的上传方法
UploadToOss(this, '上传路径oss配置信息', imgurl).then(data => {
//截取的图片
let cooperimg = data.res.requestUrls[0].split('?')[0];
this.setState({
temporaryUrl: cooperimg,
});
const { dispatch } = this.props;
//调用models的js文件中的异步方法infoImageData,在这个方法中会向后台接口发请求
dispatch({
type: 'userCenter/infoImageData',
// payload: { uid: '2',url:this.state.temporaryUrl},
payload: { uid: '2', url: this.state.temporaryUrl },
}).then(() => {
console.log(this.props.infoImageData);
this.setState({
userImg: true,
});
});
});
};
return false;
};