话不多说,直接上代码
1,先下载插件。
cnpm install image-mosaic -D
cnpm install --save vue-cropper
2,在components目录下创建一个imageEdit文件夹,文件夹下创建index.vue,index.vue中内容如下:
<template>
<div>
<el-dialog
title=""
:visible.sync="dialogImg"
:close-on-click-modal="false"
width="70%"
top="5vh"
:before-close="handleClose"
>
<div v-loading="isLoading" class="edit-img">
<vueCropper
ref="cropper"
:img="editImgUrl"
:info="false"
:output-type="'png'"
:info-true="true"
:can-move="true"
:can-scale="true"
:can-move-box="true"
:auto-crop-width="400"
:auto-crop-height="400"
:mode="'cover'"
:center-box="true"
:enlarge="2"
:full="true"
:max-img-size="200000"
@imgLoad="imgLoadCrop"
/>
<div v-if="isMosaic" class="tumo-img">
<canvas id="canvas" />
</div>
<div class="button-group">
<div class="button-item" @click="rotateHandle(1)">左旋90</div>
<div class="button-item" @click="rotateHandle(2)">右旋90</div>
<div class="button-item" @click="cropHandle">{
{ indexTab==1?'裁 剪':'取消裁剪' }}</div>
<div class="button-item" @click="mosaicHandle">{
{ !isMosaic?'打 码':'取消打码' }}</div>
<div class="button-item" @click="saveHandle">保 存</div>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
import { VueCropper } from 'vue-cropper'
import Mosaic from 'image-mosaic'
import { upLoad1 } from '@/api/files-management'
export default {
components: {
VueCropper
},
props: {
dialogImg: {
type: Boolean,
default: () => false
},
imgPath: {
type: String,
default: () => ''
}
},
data() {
return {
editImgUrl: '', // 编辑后的图片
indexTab: 1, // 1是裁剪,2是取消裁剪
isMosaic: false, // 是否打码
isLoading: true
}
},
watch: {
imgPath (val) {
this.editImgUrl = val
}
},
methods: {
imgLoadCrop() {
this.isLoading = false
},
// 裁剪
cropHandle() {
if (this.indexTab === 1) {
this.indexTab = 2
setTimeout(() => {
this.$refs.cropper.goAutoCrop()
}, 0)
} else {
this.$refs.cropper.clearCrop()
this.indexTab = 1
}
},
// 旋转
rotateHandle(val) {
this.$refs.cropper.getCropData((data) => {
this.editImgUrl = data
this.$refs.cropper.clearCrop()
setTimeout(() => {
if (val === 1) this.$refs.cropper.rotateLeft()
else this.$refs.cropper.rotateRight()
}, 0)
})
},
// 马赛克
mosaicHandle() {
this.isMosaic = !this.isMosaic
if (this.isMosaic) {
this.$refs.cropper.getCropData((data) => {
this.editImgUrl = data
this.indexTab = 1
this.$refs.cropper.clearCrop()
setTimeout(() => {
this.initMosaic()
}, 0)
})
}
},
handleClose() {
this.$refs.cropper.clearCrop()
this.editImgUrl = ''
this.indexTab = 1
this.isMosaic = false
this.$emit('closeDialog')
},
drawImageToCanvas(imageUrl) {
const canvas = document.querySelector('#canvas')
const ctx = canvas.getContext('2d')
return new Promise((resolve, reject) => {
const image = new Image()
image.crossOrigin = 'Annoymous'
image.onload = function() {
const w = image.width
const h = image.height
const yw = document.body.clientWidth * 0.7
const yh = 733
if ((w / yw) >= (h / yh)) {
image.width = yw
image.height = (yw / w) * h
} else {
image.height = yh
image.width = (yh / h) * w
}
canvas.width = image.width
canvas.height = image.height
ctx.drawImage(this, 0, 0, image.width, image.height)
resolve(ctx)
}
image.src = imageUrl
})
},
initMosaic() {
this.drawImageToCanvas(this.editImgUrl).then((ctx) => {
const mosaic = new Mosaic(ctx)
const MouseEvents = {
init() {
mosaic.context.canvas.addEventListener(
'mousedown',
MouseEvents.mousedown
)
},
mousedown() {
mosaic.context.canvas.addEventListener(
'mousemove',
MouseEvents.mousemove
)
document.addEventListener('mouseup', MouseEvents.mouseup)
},
mousemove(e) {
if (e.shiftKey) {
mosaic.eraseTileByPoint(e.layerX, e.layerY)
return
}
mosaic.drawTileByPoint(e.layerX, e.layerY)
},
mouseup() {
mosaic.context.canvas.removeEventListener(
'mousemove',
MouseEvents.mousemove
)
document.removeEventListener('mouseup', MouseEvents.mouseup)
}
}
MouseEvents.init()
})
},
saveHandle() {
if (this.isMosaic) {
var dataURL = document.querySelector('#canvas').toDataURL('image/png')
this.editImgUrl = dataURL
setTimeout(() => {
this.uploadImg()
}, 1000)
} else {
this.uploadImg()
}
},
// 上传图片
uploadImg() {
const formData = new FormData()
this.$refs.cropper.getCropBlob(data => {
formData.append('file', data, '自定义文件名')
upLoad1(formData)
.then(res => {
if (res.message === 'ok') {
this.$message.success('图片编辑成功')
} else {
this.$message.warning(res.message)
}
this.$refs.cropper.clearCrop()
this.editImgUrl = ''
this.indexTab = 1
this.isMosaic = false
this.$emit('closeDialog')
})
})
}
}
}
</script>
<style lang="scss" scoped>
.edit-img {
width: 100%;
height: 733px;
position: relative;
}
.tumo-img {
position: absolute;
width: 100%;
height: 733px;
top: 0;
left: 0;
border-radius: 2px solid red;
}
.button-group {
position: absolute;
bottom: 30px;
display: flex;
.button-item {
width: 100px;
height: 38px;
border-radius: 4px;
text-align: center;
line-height: 38px;
background-color: rgba($color: #000000, $alpha: 0.5);
color: #FFFFFF;
margin-left: 10px;
cursor: pointer;
}
}
::v-deep {
.cropper-modal {
background: rgba(0, 0, 0, .4) !important;
}
}
</style>
3,组件写好后直接在页面中调用。
<template>
<div>
<div @click="imgUrlEdit('图片地址')">图片编辑</div>
<image-edit
:dialog-img="imgEditShow"
:img-path="imgPath "
@closeDialog="closeDialog"
/>
</div>
</template>
<script>
import ImageEdit from '@/components/imageEdit'
export default {
components: {
ImageEdit
},
data() {
return {
imgEditShow: false, // 图片编辑框
imgPath: '' // 图片编辑源
}
},
method: {
closeDialog() {
this.imgEditShow = false
},
// 图片编辑
imgUrlEdit(img) {
this.imgEditShow = true
this.imgPath = img
}
}
}
</script>
这样,一个简单的裁剪,打码,选择就完成了