前段时间项目刚好需要用到图片预览裁剪压缩上传,而对于小白的我并没做过这方面的功能,可谓毫无头绪,于是上网查了下资料,发现了个很不错的插件
好了,废话不多说,先上安装包
npm或bower安装
npm install cropper
# or
bower install cropper
(https://github.com/fengyuanchen/cropperjs)
引入cropperjs
import Cropper from 'cropperjs'
构建截图所要用到的div容器
<!-- 图片裁剪遮罩层 -->
<div class="container" v-show="panel">
<div>
<img id="image" :src="url" alt="Picture">
</div>
<button type="button" class="cancelBtn" @click="cancelCrop">取消</button>
<button type="button" class="sureBtn" @click="crop">确定</button>
</div>
<div>
<img :src="pic">
<-- 给input绑定一个监听内容变化的方法,拿到上传的文件 -->
<input @change="updateHeadImg" type="file" accept="image/*"/>
</div>
添加遮罩层的样式和让image填充整个容器
.container { z-index: 99; position: fixed; left: 0; top: 0; right: 0; bottom: 0; background:rgba(0,0,0,1);}
#image {max-width: 100%;}
.cancelBtn { position: absolute; left: 5%; bottom: 50px; width: 120px; height: 60px; line-height: 60px;
border:none; padding: 0; border-radius: 5px; background:white;}
.sureBtn { position: absolute; right: 5%; bottom: 50px; width: 120px; height: 60px; line-height: 60px;
border:none; padding: 0; border-radius: 5px; background:white;}
data
data () {
return {
cropper: '',
panel: false,
croppable: false,
url: '',
}
},
初始化裁剪框
let self = this
this.cropper = new Cropper(image, {
aspectRatio: 1, // 设置裁切框的宽高比
viewMode: 2, // 限制裁剪框不超过画布的大小
dragMode: 'move', // 在裁剪框外移动会移动原图
background: false, // 显示容器的网格背景
zoomable: true, // 是否可缩放图像
autoCropArea: 1, // 裁剪区域的比例
ready: function () {
self.croppable = true
}
})
本地图片上传到canvas
updateHeadImg (e) {
let files = e.target.files || e.dataTransfer.files
let pattern = /(\.*.jpg$)|(\.*.png$)|(\.*.jpeg$)|(\.*.gif$)|(\.*.bmp$)/
if (!files.length) return
if (!pattern.test(files[0].name)) {
this.pop = '仅支持jpg/jpeg/png/gif/bmp格式的照片'
this.layer = 1
return false
}
this.panel = true
// 获取上传图片文件的url
this.url = this.getObjectURL(files[0])
// 每次替换图片要重新得到新的url
if (this.cropper) {
this.cropper.replace(this.url) // 替换图像的src并重建裁剪器
}
this.panel = true
},
获取上传图片文件的url
getObjectURL (file) {
var url = null
if (window.createObjectURL !== undefined) { // basic
url = window.createObjectURL(file)
} else if (window.URL !== undefined) { // mozilla(firefox)
url = window.URL.createObjectURL(file)
} else if (window.webkitURL !== undefined) { // webkit or chrome
url = window.webkitURL.createObjectURL(file)
}
return url
},
裁剪
crop () {
this.panel = false
let croppedCanvas
let roundedCanvas
if (!this.croppable) {
return
}
// Crop
croppedCanvas = this.cropper.getCroppedCanvas()
// Round
roundedCanvas = this.getRoundedCanvas(croppedCanvas)
// 将图片压缩 70%
this.headerImage = roundedCanvas.toDataURL('image/jpeg', 0.7)
// 上传到服务器
this.postImg()
},
取消裁剪
cancelCrop () {
this.panel = false
},
Round
getRoundedCanvas (sourceCanvas) {
var canvas = document.createElement('canvas')
var context = canvas.getContext('2d')
var width = sourceCanvas.width
var height = sourceCanvas.height
canvas.width = width
canvas.height = height
context.imageSmoothingEnabled = true // 控制图像的缩放行为
context.drawImage(sourceCanvas, 0, 0, width, height)
context.globalCompositeOperation = 'destination-in' // 在源图像中显示目标图像。只有源图像内的目标图像部分会被显示,源图像是透明的。
context.beginPath()
context.arc(width / 2, height / 2, Math.min(width, height) / 2, 0, 2 * Math.PI, true)
context.fill()
return canvas
},
上传到服务器
postImg () {
// 这边写图片的上传
axios.post('接口', {'图片地址': this.headerImage}).then((res) => {
console.log('成功')
})
},
当初以为这样就完事了,可发现当再次进行上传的时候发现图片会下滑,翻看了一下文档,发现官方是使用动态添加裁剪容器的方法进行操作的。
既然知道了每执行一次都要重新渲染画布,那就很简单了,我们把初始化事件添加到watch上,当重新选择的时候重新渲染画布
/* 把画布清空 */
if (document.querySelector('.cropper-container')) {
document.querySelector('.cropper-container').remove()
}
this.cropper = ''
// 重新渲染画布
let image = document.getElementById('image')
let self = this
this.cropper = new Cropper(image, {
aspectRatio: this.edEle.width / this.edEle.height, // 设置裁切框的宽高比
viewMode: 2, // 限制裁剪框不超过画布的大小
dragMode: 'move', // 在裁剪框外移动会移动原图
background: false, // 显示容器的网格背景
zoomable: true, // 是否可缩放图像
autoCropArea: 1, // 裁剪区域的比例
ready: function () {
self.croppable = true
}
})
小白初来驾到,如有错误请告知,让我们互相学习学习
网友评论