利用vue-cropper做的关于图片裁剪、压缩、上传、预览等做的一个公共组件
自己做的弹窗裁剪
<template>
<Modal
class="ct-personal-info"
v-model="modalVisible"
width="550"
footer-hide
>
<h2 slot="header">中教信息</h2>
<div class="ct-personal-info-content" v-if="!showCropper">
<div
class="ct-head-portrait"
@click="handlerChangePhoto"
@mouseenter="mouseenterImg"
@mouseleave="mouseleaveImg"
>
<img class="head-photo-img" :src="headPhotoSrc" />
<div v-if="showCameraIcon" class="camera-icon-wrapper">
<Icon type="ios-camera" class="camera-icon" size="40" />
</div>
</div>
<input
ref="fileInput"
type="file"
class="file-hidden"
accept="image/*"
@change="handlerGetImg($event)"
/>
<div class="ct-name">
<label>姓名:</label>
<Input class="ct-name-ipt" v-model="ctName" placeholder="请输入姓名" />
</div>
<div class="ct-info-change-icon">
<Icon
class="tabel-teacher-houseNumAll-icon-1 change-icon"
custom="iconfont icon-bianji_moren-"
@click="handlerSubmitInfo"
/>
</div>
</div>
<div class="tailor-photo" v-if="showCropper">
<div class="cropper-wrapper">
<VueCropper
ref="cropper"
:img="option.imgUrl"
:outputSize="option.size"
:outputType="option.outputType"
:autoCrop="option.autoCrop"
:autoCropWidth="option.autoCropWidth"
:autoCropHeight="option.autoCropHeight"
:fixedBox="option.fixedBox"
></VueCropper>
</div>
<div class="btns-group">
<Button class="photo-btn" @click="handlerCancelCropper">取消</Button>
<Button class="photo-btn" type="primary" @click="handlerRotateRight"
>顺时针旋转</Button
>
<Button class="photo-btn" type="primary" @click="handlerRotateLeft"
>逆时针旋转</Button
>
<Button type="primary" @click="handlerFinishPhoto">确定</Button>
</div>
</div>
</Modal>
</template>
<script type="text/javascript">
import { ajaxHelper, mapState, message } from 'utils';
import { postUpdateStudyPlanCtPhotoApi } from '@/api/studentDetail';
import regexp from 'const/regexp';
import { VueCropper } from 'vue-cropper';
export default {
name: 'ct-personal-info',
components: { VueCropper },
data() {
return {
modalVisible: true,
ctName: '',
option: {
imgUrl: '',
size: 0,
autoCrop: true,
autoCropWidth: 200,
autoCropHeight: 200,
fixedBox: true,
outputType: 'png',
},
showCropper: false,
headPhotoSrc: '',
showCameraIcon: false,
finishCropperData: {},
fileTargetVal: {},
};
},
computed: {
...mapState({
email: state => state.user.email,
learningPlanEmployeeName: state => state.user.learningPlanEmployeeName,
learningPlanEmployeeAvatar: state =>
state.user.learningPlanEmployeeAvatar,
}),
},
watch: {
modalVisible: {
handler(newValue) {
if (newValue) {
this.ctName = this.learningPlanEmployeeName;
this.headPhotoSrc = this.learningPlanEmployeeAvatar;
}
},
immediate: true,
},
showCropper(newValue, oldValue) {
if (!newValue) {
this.option.imgUrl = '';
}
},
},
methods: {
handlerChangePhoto() {
this.$refs.fileInput.click();
this.showCropper = true;
},
handlerCancelCropper() {
this.showCropper = false;
},
mouseenterImg() {
this.showCameraIcon = true;
},
mouseleaveImg() {
this.showCameraIcon = false;
},
//选择本地图片
handlerGetImg(e) {
let _this = this;
//上传图片
let file = e.target.files[0];
this.fileTargetVal = file;
if (!regexp.imgType.test(e.target.value)) {
message('warning', '图片类型必须是jpeg,jpg,png,bmp中的一种');
return false;
}
let reader = new FileReader();
reader.onload = e => {
let data;
if (typeof e.target.result === 'object') {
// 把Array Buffer转化为blob 如果是base64不需要
data = window.URL.createObjectURL(new Blob([e.target.result]));
} else {
data = e.target.result;
}
_this.option.imgUrl = data;
};
//转化为base64;
// reader.readAsDataURL(file);
// 转化为blob
reader.readAsArrayBuffer(file);
},
//顺时针旋转
handlerRotateRight() {
this.$refs.cropper.rotateRight();
},
//逆时针旋转
handlerRotateLeft() {
this.$refs.cropper.rotateLeft();
},
handlerFinishPhoto() {
// 获取截图的blob数据
this.$refs.cropper.getCropBlob(data => {
this.finishCropperData = data;
//关闭裁剪
this.showCropper = false;
//取消相机icon
this.mouseleaveImg();
//blob转回imgsrc用于预览
this.headPhotoSrc = window.URL.createObjectURL(data);
});
},
async postUpdateStudyPlanCtPhoto() {
let res = await ajaxHelper(
postUpdateStudyPlanCtPhotoApi.bind(
null,
this.reqUpdateStudyPlanCtPhoto()
)
);
res && this.resUpdateStudyPlanCtPhoto();
},
reqUpdateStudyPlanCtPhoto() {
let formData = new FormData();
formData.append(
'learning_plan_employee_avatar_file',
this.finishCropperData
);
formData.append('learning_plan_employee_name', this.ctName);
formData.append('employee', this.email);
return formData;
},
resUpdateStudyPlanCtPhoto() {
message('success', '保存成功');
//关闭弹窗
// this.modalVisible=false;
},
handlerSubmitInfo() {
//判断昵称和头像src有无即可,不需要判断blob对象
if (!this.ctName || !this.headPhotoSrc) {
message('warning', '请补充完整信息');
return;
}
this.postUpdateStudyPlanCtPhoto();
},
},
};
</script>
<style scoped lang="scss">
.ct-personal-info {
.ct-personal-info-content {
display: flex;
align-items: center;
}
.ct-head-portrait {
position: relative;
width: 100px;
height: 100px;
border-radius: 50%;
border: solid 1px;
margin-right: 8px;
overflow: hidden;
.head-photo-img {
position: absolute;
width: 100%;
height: 100%;
z-index: 10;
}
.camera-icon-wrapper {
width: 100%;
height: 100%;
position: absolute;
text-align: center;
z-index: 100;
background-color: rgba(4, 6, 8, 0.2);
&::before {
content: ' ';
display: inline-block;
height: 100%;
width: 1%;
vertical-align: middle;
}
}
}
.file-hidden {
display: none;
}
.ct-name {
display: flex;
align-items: center;
margin-right: 8px;
& > label {
width: 40px;
}
.ct-name-ipt {
width: 240px;
}
}
.change-icon {
cursor: pointer;
&:hover {
color: rgba(24, 144, 255, 1);
}
}
.tailor-photo {
.cropper-wrapper {
width: 500px;
height: 500px;
}
.btns-group {
display: flex;
justify-content: flex-end;
margin-top: 20px;
.photo-btn {
margin-right: 8px;
}
}
}
}
</style>
注意
上传文件流需要使用FormData对象,将需要参数通过append方式加入,最终axios请求只需要data:formData即可
例如:
reqUpdateStudyPlanCtPhoto() {
let formData = new FormData();
//将参数一一添加
formData.append(
'learning_plan_employee_avatar_file',
this.finishCropperData
);
formData.append('learning_plan_employee_name', this.ctName);
formData.append('employee', this.email);
return formData;
},
//data:formData
function postUpdateStudyPlanCtPhotoApi(formData) {
return Axios({
url: ' /api/permission/employee/update/',
method: 'post',
data: formData,
});
}
???
不知道为啥,默认裁剪框宽高无效。难受。