- 封面图片
子组件imageCropper
<template>
<div class="imageCropper">
<div class="imageCropper-show"
:style="{'width': cropperStyle.width + 'px', 'height': cropperStyle.height + 'px'}">
<img v-if="options.img"
:src="options.img"
class="imageCropper-show-img" />
<div v-if="options.img"
class="image-tools">
<span class="image-btn"
@click="editCropper()"><i class="el-icon-edit"
title="编辑"></i></span>
<span class="image-btn"><i class="el-icon-delete"
title="删除"
@click="deleteImage()"></i></span>
</div>
<div v-else
class="image-add" @click="editCropper()">
<i class="el-icon-plus"
title="添加"
></i>
</div>
</div>
<div>请上传格式如<span style="color:#f67979"> jpg/png </span>的图片文件;推荐分辨率为 <span style="color:#f67979"> {{cropperStyle.width+"*"+cropperStyle.height}}</span> </div>
<!-- 弹框内容 -->
<el-dialog title="裁剪图片(选择图片后拖动方框或点击左侧操作按钮来裁剪图片)"
:visible.sync="cropperVisible"
v-if="cropperVisible"
append-to-body
:width="dialogWidth">
<div class="cropper-box"
:style="{ 'height': dialogHeight}">
<div class="cropper-left">
<vue-cropper ref="cropper"
:img="options.img"
:info="true"
:autoCrop="options.autoCrop"
:autoCropWidth="options.autoCropWidth"
:autoCropHeight="options.autoCropHeight"
:fixedBox="options.fixedBox"
:full="options.full"
:height="options.height"
:infoTrue="options.infoTrue"
:enlarge="options.enlarge"
:outputSize="options.outputSize"
@realTime="realTime" />
<div class="cropper-tools">
<el-upload action="#"
:http-request="requestUpload"
:show-file-list="false"
:before-upload="beforeUpload">
<el-button type="primary"
plain>
<i class="el-icon-upload el-icon--right"></i>
选择
</el-button>
</el-upload>
<el-button-group class="tools-group">
<el-button type="primary"
plain
icon="el-icon-plus"
@click="changeScale(1)">放大</el-button>
<el-button type="primary"
plain
icon="el-icon-minus"
@click="changeScale(-1)">缩小</el-button>
<el-button type="primary"
plain
icon="el-icon-refresh-left"
@click="rotateLeft()">左旋</el-button>
<el-button type="primary"
plain
icon="el-icon-refresh-right"
@click="rotateRight()">右旋</el-button>
</el-button-group>
</div>
</div>
<div class="cropper-right">
<div class="cropper-tips">预览图片(点击确认上传此图)</div>
<div class="cropper-preview"
:style="{'width': previews.w + 'px', 'height': previews.h + 'px', 'overflow': 'hidden', 'margin': '5px'}"
title="预览图片">
<div :style="previews.div">
<img :src="previews.url"
:style="previews.img" />
</div>
</div>
<div class="preview-submit">
<el-button type="primary"
@click="uploadImg()">确 认</el-button>
</div>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
import { VueCropper } from "vue-cropper"
import * as fileStore from "@/api/base/fileStore";
export default {
name: "imageCropper",
components: { VueCropper },
props: {
imgUrl: {
type: String
},
cropperStyle: {
type: Object,
default: () => {
return {
width: 300,
height: 200
}
}
}
},
watch: {
imgUrl(params) {
this.options.img = params
}
},
computed: {
dialogWidth() {
if (
this.cropperStyle.width * 2 <
Number(document.body.clientWidth) * 0.66
) {
return "66vw"
} else {
return "100vw"
}
},
dialogHeight() {
if (this.cropperStyle.height > Number(document.body.clientWidth) * 0.8) {
return "100vh"
} else {
return this.cropperStyle.height + 100 + "px"
}
}
},
data() {
return {
cropperVisible: false,
visible: false,
options: {
img: "",
autoCrop: true,
autoCropWidth: 400,
autoCropHeight: 300,
fixedBox: true,
height: true,
full: false,
infoTrue: false,
enlarge: 1,
outputSize: 1,
},
previews: {},
fileName: ''
}
},
created() {
this.options.autoCropWidth = this.cropperStyle.width
this.options.autoCropHeight = this.cropperStyle.height
if(this.imgUrl){
this.options.img = this.imgUrl
}
},
methods: {
deleteAction() {
this.options.img = "";
},
deleteImage() {
this.$emit("deleteImage", "")
},
editCropper() {
this.cropperVisible = true
},
requestUpload() {},
rotateLeft() {
this.$refs.cropper.rotateLeft()
},
rotateRight() {
this.$refs.cropper.rotateRight()
},
changeScale(num) {
num = num || 1
this.$refs.cropper.changeScale(num)
},
beforeUpload(file) {
this.fileName = file.name;
if (file.type.indexOf("image/") == -1) {
this.$modal.msgError(
"文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。"
)
} else {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => {
this.options.img = reader.result
}
}
},
uploadImg() {
this.$refs.cropper.getCropBlob((data) => {
var file = new File([data], this.fileName);
let form = new FormData();
form.append("file", file);
fileStore.uploadFiles(form).then((response) => {
this.cropperVisible = false
this.options.img = fileStore.getImgUrl(response.data.fileId)
this.$emit("changeImg", response.data.fileId, response.data.type)
this.$message.success("提交成功")
})
})
},
realTime(data) {
console.log(data, '======')
this.previews = data
}
}
}
</script>
<style scoped lang="less">
.imageCropper {
width: 100%;
height: 100%;
overflow: hidden;
}
.imageCropper-show {
position: relative;
border: 1px solid #c0c4cc;
cursor: pointer;
.imageCropper-show-img {
width: 100%;
height: 100%;
}
.image-tools {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
cursor: default;
text-align: center;
color: #fff;
opacity: 0;
font-size: 25px;
background-color: rgba(0, 0, 0, 0.5);
transition: opacity 0.3s;
display: flex;
justify-content: center;
align-items: center;
&:hover {
opacity: 1;
}
.image-btn {
display: inline-block;
padding: 0 10px;
cursor: pointer;
}
}
.image-add {
width: 100%;
height: 100%;
font-size: 20px;
display: flex;
justify-content: center;
align-items: center;
.el-icon-plus {
font-size: 30px;
font-weight: 600;
}
}
}
.cropper-box {
min-height: 400px;
display: flex;
justify-content: space-around;
.cropper-left {
width: 49%;
height: calc(100% - 60px);
position: relative;
}
.cropper-right {
width: 49%;
height: calc(100% - 60px);
border: 2px dashed #1890ff;
text-align: center;
position: relative;
display: flex;
align-items: center;
justify-content: center;
.cropper-preview {
background: #000000;
z-index: 2;
}
.cropper-tips {
z-index: 1;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 1.2rem;
color: #1890ff;
}
}
}
.cropper-tools {
width: 100%;
height: 50px;
position: absolute;
left: 0;
bottom: -60px;
display: flex;
.tools-group {
margin-left: 10px;
}
}
.preview-submit {
width: 100%;
height: 50px;
text-align: center;
position: absolute;
right: 0;
bottom: -60px;
}
</style>
- 父组件应用
<el-col :span="24">
<el-form-item label="图片" prop="img">
<imageCropper ref="imageCropper"
:cropperStyle="cropperStyle"
:imgUrl.sync="form.img"
@changeImg="changeImg"
@deleteImage="deleteImage"/>
</el-form-item>
</el-col>
import imageCropper from "@/components/imageCropper/index.vue"
data(){
return{
cropperStyle:{
width:592,
height:256,
},
form:{
img:'',
pictures :'',
fileType :'',
}
},
methods:{
changeImg(fileId, type) {
this.form.pictures = fileId;
this.form.fileType = type;
console.log(fileId, type)
},
deleteImage() {
this.form.pictures = '';
this.form.fileType = '';
this.$refs.imageCropper.deleteAction();
},
}