vue中 通过cropperjs 实现图片裁剪
cropperjs 官方文档: https://www.npmjs.com/package/cropperjs
最终效果图
具体实现
- 安装 cropperjs
npm install cropperjs --save
- 引入 cropperjs
import Cropper from 'cropperjs'
import 'cropperjs/dist/cropper.css'
- 自定义 裁剪图片弹窗 组件
<template>
<el-dialog title="图片裁剪" :visible.sync="dialogVisible" width="1300px" :append-to-body="true">
<div class="cropper-content">
<!-- 剪裁框 -->
<div class="cropper">
<img ref="image" :src="imgFile" alt="">
</div>
<!-- 预览框 -->
<div
class="show-preview"
:style="{
overflow: 'hidden',
margin: '0 25px',
display: 'flex',
'align-items': 'center'
}"
>
<div class="preview before" />
</div>
</div>
<div class="footer-btn">
<!-- 缩放旋转按钮 -->
<div class="scope-btn">
<el-tooltip class="item" effect="dark" content="放大" placement="top">
<el-button icon="el-icon-zoom-in" @click="cropperzoom(0.05)" />
</el-tooltip>
<el-tooltip class="item" effect="dark" content="缩小" placement="top">
<el-button icon="el-icon-zoom-out" @click="cropperzoom(-0.05)" />
</el-tooltip>
<el-tooltip
class="item"
effect="dark"
content="逆时针旋转"
placement="top"
>
<el-button
icon="el-icon-refresh-left"
@click="cropperRotate(-90)"
/>
</el-tooltip>
<el-tooltip
class="item"
effect="dark"
content="顺时针旋转"
placement="top"
>
<el-button
icon="el-icon-refresh-right"
@click="cropperRotate(90)"
/>
</el-tooltip>
</div>
<div class="upload-btn">
<el-button class="btn" @click="closeCropper">取消</el-button>
<el-button
type="primary"
@click="sureSave()"
>确定</el-button>
</div>
</div>
</el-dialog>
</template>
<script>
import Cropper from 'cropperjs'
import 'cropperjs/dist/cropper.css'
export default {
props: {
imgFile: {
type: String,
default: ''
},
visible: {
type: Boolean,
default: false
}
},
data() {
return {
myCropper: null,
afterImg: ''
}
},
computed: {
dialogVisible: {
get() {
return this.visible
},
set(val) {
this.$emit('update:visible', val)
}
}
},
watch: {
imgFile(val) {
if (val) {
setTimeout(() => {
if (this.myCropper) {
// 这里很重要,不然弹窗再次弹出后图片不会更新
this.myCropper.destroy()
this.init()
} else {
this.init()
}
})
}
},
visible: {
handler: function (val) {
if (!val) {
this.myCropper.destroy()
}
}
}
},
methods: {
closeCropper() {
this.$emit('closeCropper')
},
init() {
this.myCropper = new Cropper(this.$refs.image, {
viewMode: 1,
dragMode: 'move',
preview: '.before',
background: false,
autoCropArea: 0.8,
zoomOnWheel: true
})
},
sureSave() {
this.afterImg = this.myCropper
.getCroppedCanvas({
imageSmoothingQuality: 'high'
})
.toDataURL('image/jpeg')
this.$emit('cropperImg', this.base64ToBlob(this.afterImg))
},
base64ToBlob(code) {
const parts = code.split(';base64,')
const contentType = parts[0].split(':')[1]
const raw = window.atob(parts[1])
const rawLength = raw.length
const uInt8Array = new Uint8Array(rawLength)
for (let i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i)
}
return new Blob([uInt8Array], {
type: contentType
})
},
// 缩放
cropperzoom(val) {
this.myCropper.zoom(val)
},
// 旋转
cropperRotate(val) {
this.myCropper.rotate(val)
}
}
}
</script>
<style lang="scss" scoped>
.cropper {
border: 1px solid #fff;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMzTjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC);
img{
width: 100%;
opacity: 0;
}
}
.cropper-content {
display: flex;
display: -webkit-flex;
justify-content: flex-end;
-webkit-justify-content: flex-end;
}
.cropper-content .cropper {
// width: 550px;
// height: 400px;
width: 600px;
height: 450px;
overflow: hidden;
}
.cropper-content .show-preview {
flex: 1;
-webkit-flex: 1;
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 #468ac8;
background: #cccccc;
}
.footer-btn {
margin-top: 30px;
display: flex;
display: -webkit-flex;
justify-content: flex-end;
-webkit-justify-content: flex-end;
}
.footer-btn .scope-btn {
width: 260px;
display: flex;
display: -webkit-flex;
justify-content: space-between;
-webkit-justify-content: space-between;
}
.footer-btn .scope-btn span {
display: inline-block;
padding: 10px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
border-radius: 5px;
background: #fff;
cursor: pointer;
}
.footer-btn .scope-btn span i {
font-size: 32px;
color: #333333;
}
.footer-btn .upload-btn {
flex: 1;
-webkit-flex: 1;
display: flex;
display: -webkit-flex;
justify-content: flex-end;
-webkit-justify-content: flex-end;
margin-right: 25px;
.btn {
padding: 0 10px;
height: 29px;
}
}
.solide {
margin-left: 25px;
width: 200px;
}
.before {
width: 100%;
height: 100%;
overflow: hidden;
}
</style>
- 使用组件
import cropper from './cropper.vue'
<cropper :imgFile="originBase64" :visible.sync="cropperVisible" v-bind="$attrs" @cropperImg="cropperImg" @closeCropper="closeCropper" v-on="$listeners" />
参考地址:https://www.jianshu.com/p/5f5aafe9e895