VueCropper + Element 上传并剪裁图片
效果图
安装插件
npm install vue-cropper
VueCropper组件代码
<template>
<div>
<el-dialog title="图片剪裁" :visible.sync="cropperShow" append-to-body width="1000px" center>
<div class="cropper-content">
<div class="cropper-box">
<div class="cropper">
<vue-cropper ref="cropper" :img="img" :outputSize="option.outputSize" :outputType="option.outputType" :info="option.info" :canScale="option.canScale" :autoCrop="option.autoCrop" :autoCropWidth="autoCropWidth" :autoCropHeight="autoCropHeight" :fixed="option.fixed" :fixedNumber="option.fixedNumber" :full="option.full" :fixedBox="fixedBox" :canMove="option.canMove" :canMoveBox="option.canMoveBox" :original="option.original" :centerBox="option.centerBox" :height="option.height" :infoTrue="option.infoTrue" :maxImgSize="option.maxImgSize" :enlarge="option.enlarge" :mode="option.mode" @realTime="realTime" @imgLoad="imgLoad">
</vue-cropper>
</div>
<!--底部操作工具按钮-->
<div class="footer-btn">
<div class="scope-btn">
<el-button size="mini" type="danger" plain icon="el-icon-zoom-in" @click="changeScale(1)">放大</el-button>
<el-button size="mini" type="danger" plain icon="el-icon-zoom-out" @click="changeScale(-1)">缩小</el-button>
<el-button size="mini" type="danger" plain @click="rotateLeft">↺ 左旋转</el-button>
<el-button size="mini" type="danger" plain @click="rotateRight">↻ 右旋转</el-button>
</div>
<div class="upload-btn">
<el-button size="mini" type="success" @click="uploadImg('blob')">上传图片 <i class="el-icon-upload"></i></el-button>
</div>
</div>
</div>
<!--预览效果图-->
<div class="show-preview">
<div :style="previews.div" class="preview">
<img :src="previews.url" :style="previews.img">
</div>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
import {
VueCropper } from 'vue-cropper'
import {
cropperUpload } from '@/api/common'
export default {
name: "CropperImage",
components: {
VueCropper
},
data () {
return {
show: this.cropperShow,
previews: {
},
option: {
// img: '', //裁剪图片的地址
outputSize: 1, //裁剪生成图片的质量(可选0.1 - 1)
outputType: 'jpeg', //裁剪生成图片的格式(jpeg || png || webp)
info: true, //裁剪框的大小信息,图片大小信息
canScale: true, //图片是否允许滚轮缩放
autoCrop: true, //是否默认生成截图框
// autoCropWidth: 300, //默认生成截图框宽度
// autoCropHeight: 200, //默认生成截图框高度
fixed: false, //是否开启截图框宽高固定比例
fixedNumber: [1.5, 1], //截图框的宽高比例
full: true, //false按原比例裁切图片,不失真
// fixedBox: false, //固定截图框大小,不允许改变
canMove: true, //上传图片是否可以移动
canMoveBox: true, //截图框能否拖动
original: false, //上传图片按照原始比例渲染
centerBox: false, //截图框是否被限制在图片里面
height: true, //是否按照设备的dpr 输出等比例图片
infoTrue: false, //true为展示真实输出图片宽高,false展示看到的截图框宽高
maxImgSize: 3000, //限制图片最大宽度和高度
enlarge: 1, //图片根据截图框输出比例倍数
// mode: '230px 150px' //图片默认渲染方式
}
};
},
props: {
cropperShow: {
type: Boolean,
default: false
},
img: {
type: String,
default: ''
},
autoCropWidth: {
type: Number,
default: 100
},
autoCropHeight: {
type: Number,
default: 100
},
fileinfo: {
type: Object,
default: null,
},
fixedBox: {
type: Boolean,
default: true
}
},
methods: {
//初始化函数
imgLoad (msg) {
},
//图片缩放
changeScale (num) {
num = num || 1
this.$refs.cropper.changeScale(num)
},
//向左旋转
rotateLeft () {
this.$refs.cropper.rotateLeft()
},
//向右旋转
rotateRight () {
this.$refs.cropper.rotateRight()
},
//实时预览函数
realTime (data) {
this.previews = data
},
//选择图片
selectImg (e) {
let file = e.target.files[0]
if (!/\.(jpg|jpeg|png|JPG|PNG)$/.test(e.target.value)) {
this.$message({
message: '图片类型要求:jpeg、jpg、png',
type: "error"
});
return false
}
//转化为blob
let reader = new FileReader()
reader.onload = (e) => {
let data
if (typeof e.target.result === 'object') {
data = window.URL.createObjectURL(new Blob([e.target.result]))
} else {
data = e.target.result
}
this.option.img = data
}
//转化为base64
reader.readAsDataURL(file)
},
//上传图片
uploadImg (type) {
let _this = this
if (type === 'blob') {
// 获取截图的blob数据
this.$refs.cropper.getCropBlob(async (data) => {
let previewImg = URL.createObjectURL(data)
let formData = new FormData();
let file_name = this.fileinfo.uid + this.fileinfo.name//重命名
formData.append('file', data, file_name)
// 调用上传图片接口
cropperUpload(formData).then((result) => {
console.log(result);
let msg = {
uploadImg: previewImg, // 本地地址
dataImg: result.data.url // 接口返回的线上地址
}
this.$emit("cropperImg", msg)
}).catch((err) => {
console.log(err);
});
})
}
}
}
}
</script>
<style scoped lang="sass">
.cropper-content
display: flex
display: -webkit-flex
justify-content: flex-end
.cropper-box
flex: 2
width: 100%
.cropper
width: auto
height: 400px
.show-preview
flex: 1
-webkit-flex: 1
display: flex
display: -webkit-flex
justify-content: center
.preview
margin-left: 20px
overflow: hidden
border: 1px solid #67c23a
background: #cccccc
.footer-btn
margin-top: 30px
display: flex
display: -webkit-flex
justify-content: flex-end
.scope-btn
display: flex
display: -webkit-flex
justify-content: space-between
padding-right: 10px
.upload-btn
flex: 1
-webkit-flex: 1
display: flex
display: -webkit-flex
justify-content: center
.btn
outline: none
display: inline-block
line-height: 1
white-space: nowrap
cursor: pointer
-webkit-appearance: none
text-align: center
-webkit-box-sizing: border-box
box-sizing: border-box
outline: 0
-webkit-transition: 0.1s
transition: 0.1s
font-weight: 500
padding: 8px 15px
font-size: 12px
border-radius: 3px
color: #fff
background-color: #409eff
border-color: #409eff
margin-right: 10px
</style>
父组件使用
<el-form-item label="图片" prop="imageUrl">
<el-upload class="avatar-uploader" :action="uploadUrl()" :headers="uploadHeaders" :show-file-list="false" :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload" :auto-upload="false" :on-change="onChange">
<img v-if="form.imageUrl" :src="form.imageUrl ? getImageUrl(form.imageUrl) : coverImg" class="avatar" alt="" />
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
<cropper :cropperShow.sync="cropperShow" :fileinfo="fileinfo" :img="croperImg" :autoCropWidth="375" :autoCropHeight="211" @cropperImg="cropperImg"></cropper>
</el-form-item>
getImageUrl (path) {
return 地址前缀 + "/" + path;
},
handleAvatarSuccess (res, file) {
this.coverImg = URL.createObjectURL(file.raw);
this.form.imageUrl = res.data.url;
},
beforeAvatarUpload (file) {
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
this.$message.error('上传图片大小不能超过 2MB!');
}
return isLt2M;
},
onChange (file) {
if (file.status == "ready") {
this.croperImg = window.URL.createObjectURL(new Blob([file.raw]));
this.fileinfo = file
this.cropperShow = true
}
},
cropperImg (val) {
// console.log("剪裁后的图片",val);
this.coverImg = val.uploadImg;
this.form.imageUrl = val.dataImg;
this.cropperShow = false
},
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409eff;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 375px;
height: 211px;
line-height: 211px;
text-align: center;
}
.avatar {
width: 375px;
height: 211px;
display: block;
}