1.安装
npm install vue-cropper
2.main.js
import VueCropper from 'vue-cropper'
Vue.use(VueCropper)
3.裁剪组件弹框 cropperDlg.vue
<template>
<el-dialog title="图片剪裁" :visible.sync="dialogVisible" class="crop-dialog" append-to-body>
<div>
<div class="cropper-content">
<!-- 剪裁框 -->
<div class="cropper">
<VueCropper
ref="cropper"
:img="option.img"
:outputSize="option.size"
:outputType="option.outputType"
:info="true"
:full="option.full"
:canMove="option.canMove"
:canMoveBox="option.canMoveBox"
:original="option.original"
:autoCrop="option.autoCrop"
:autoCropWidth="option.autoCropWidth"
:autoCropHeight="option.autoCropHeight"
:fixedBox="option.fixedBox"
@realTime="realTime"
:fixed="option.fixed"
listType="picture-card"
:fixedNumber="fixedNumber"
></VueCropper>
</div>
<!-- 预览框 -->
<div
class="show-preview"
:style="{
width: '50%',
height: '300px',
overflow: 'hidden',
margin: '0 25px',
display: 'flex',
'align-items': 'center',
}"
>
<div :style="previews.div" class="preview">
<img :src="previews.url" :style="previews.img" />
</div>
</div>
</div>
<div class="footer-btn">
<!-- 缩放旋转按钮 -->
<div class="scope-btn">
<el-button type="primary" icon="el-icon-zoom-in" @click="changeScale(1)"></el-button>
<el-button type="primary" icon="el-icon-zoom-out" @click="changeScale(-1)"></el-button>
<el-button type="primary" @click="rotateLeft">逆时针旋转</el-button>
<el-button type="primary" @click="rotateRight">顺时针旋转</el-button>
</div>
<!-- 确认上传按钮 -->
<div class="upload-btn">
<el-button type="primary" @click="uploadImg('blob')">确定</el-button>
</div>
</div>
</div>
</el-dialog>
</template>
<script>
export default {
data() {
return {
previews: {}, // 预览数据
option: {
img: '', // 裁剪图片的地址 (默认:空)
size: 1, // 裁剪生成图片的质量 (默认:1)
full: true, // 是否输出原图比例的截图 选true生成的图片会非常大 (默认:false)
outputType: 'png', // 裁剪生成图片的格式 (默认:jpg)
canMove: true, // 上传图片是否可以移动 (默认:true)
original: false, // 上传图片按照原始比例渲染 (默认:false)
canMoveBox: true, // 截图框能否拖动 (默认:true)
autoCrop: true, // 是否默认生成截图框 (默认:false)
autoCropWidth: 400, // 默认生成截图框宽度 (默认:80%)
autoCropHeight: 400, // 默认生成截图框高度 (默认:80%)
fixedBox: false, // 固定截图框大小 不允许改变 (默认:false)
fixed: true, // 是否开启截图框宽高固定比例 (默认:true)
fixedNumber: [1.5, 1], // 截图框比例 (默认:[1:1])
},
downImg: '#',
}
},
props: ['imgFile', 'fixedNumber', 'dialogVisible'],
mounted() {
this.$nextTick(() => {
var 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(this.imgFile)
// 转化为blob
reader.readAsArrayBuffer(this.imgFile);
})
},
methods: {
changeScale(num) {
// 图片缩放
num = num || 1
this.$refs.cropper.changeScale(num)
},
rotateLeft() {
// 向左旋转
this.$refs.cropper.rotateLeft()
},
rotateRight() {
// 向右旋转
this.$refs.cropper.rotateRight()
},
// Update() {
// // this.file = this.imgFile
// this.option.img = this.imgFile.url
// },
realTime(data) {
// 实时预览
this.previews = data
},
uploadImg(type) {
// 将剪裁好的图片回传给父组件
event.preventDefault()
let that = this
if (type === 'blob') {
this.$refs.cropper.getCropBlob((data) => {
that.$emit('upload', data)
})
} else {
this.$refs.cropper.getCropData((data) => {
that.$emit('upload', data)
})
}
},
},
}
</script>
<style>
.cropper-content {
display: flex;
display: -webkit-flex;
justify-content: flex-end;
-webkit-justify-content: flex-end;
width: 100%;
}
.cropper-content .cropper {
width: 50%;
height: 300px;
}
.cropper-content .show-preview {
width: 50%;
height: 300px;
display: flex;
display: -webkit-flex;
justify-content: center;
-webkit-justify-content: center;
overflow: hidden;
border: 1px solid #cccccc;
/* background: #cccccc; */
margin-left: 40px;
}
.preview {
overflow: hidden;
border: 1px solid #e9ebef;
background: #e9ebef;
}
.footer-btn {
margin-top: 30px;
display: flex;
display: -webkit-flex;
justify-content: flex-end;
-webkit-justify-content: flex-end;
}
.footer-btn .scope-btn {
width: 50%;
display: flex;
display: -webkit-flex;
}
.footer-btn .upload-btn {
width: 50%;
display: flex;
display: -webkit-flex;
justify-content: center;
-webkit-justify-content: center;
padding: 0 14px;
}
.footer-btn .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;
margin: 0;
-webkit-transition: 0.1s;
transition: 0.1s;
font-weight: 500;
padding: 8px 15px;
font-size: 12px;
border-radius: 3px;
color: #fff;
background-color: #67c23a;
border-color: #67c23a;
}
</style>
vue文件使用 裁剪获取blob
<template>
<div>
<el-upload
v-loading="loading"
:limit="limit"
ref="upload"
action="#"
class="img-uploader"
list-type="picture-card"
:file-list="fileList"
:on-preview="handlePreview"
:before-upload="beforeUpload"
:http-request="httpRequest"
:on-exceed="handleExceed"
:disabled="disabled"
> <div class="upload-icon">
<i class="el-icon-plus"></i>
</div> </el-upload>
<CropperDlg
v-if="showCropper"
:dialogVisible.sync="showCropper"
:img-file="currentFile"
ref="vueCropper"
:fixedNumber="fixedNumber"
@upload="upload"
></CropperDlg>
</div>
</template>
<script>
import CropperDlg from '@/components/cropperDlg'
export default {
components: { CropperDlg },
data() {
return {
fileList:[],
currentFile: {},
fixedNumber: [10, 7],
showCropper: false,//裁剪弹框
isCropper:true,//上传之前是否显示裁剪
}
},
methods: {
upload(data) { //裁剪成功后获取的图片
console.log('data: ', data)
},
// el-upload 上传之前
beforeUpload(file) {
if (this.isCropper) {//显示裁剪
this.currentFile = file
this.showCropper = true
return false
}
return true
},
// 附件改变
handleChange(file, fileList) {},
// 文件个数限制
handleExceed(files, fileList) {
this.$message.warning(`请最多上传 ${this.limit} 个文件。`)
},
// 附件上传
httpRequest(file) {
if (!beforeFileUpload(file?.file, this.fileList)) return
console.log('测试file', file)
},
},
}
</script>
<style lang="less" scoped>