vue-cropper是一个可以进行图片剪辑的插件,使用于vue
github地址:https://github.com/xyxiao001/vue-cropper
1、下载vue-cropper
npm install vue-cropper
2、引用(组件引入)
2.1、引入下载的vue-cropper
import { VueCropper } from 'vue-cropper'
2.2、component引入组件
components: {
VueCropper
},
2.3、页面中使用
<div class="cropper" :style='{width: `${imgObj.width}px`, height: `${imgObj.height}px`}'>
<vueCropper
ref="cropper"
:img="option.img"
:outputSize="option.outputSize"
:outputType="option.outputType"
:canScale='option.canScale'
:autoCrop='option.autoCrop'
:autoCropWidth='option.autoCropWidth'
:autoCropHeight='option.autoCropHeight'
:canMoveBox='option.canMoveBox'
:canMove='option.canMove'
:centerBox='option.centerBox'
:info='option.info'
:fixedBox='option.fixedBox'
@realTime='realTime'
></vueCropper>
</div>
2.4、data中定义的数据
option: {
img: require('../assets/preview.jpg'), // 裁剪图片地址,这里可以本地图片或者链接,链接不用require
outputSize: 1, // 裁剪生成图片质量
outputType: 'jepg', // 裁剪生成图片格式
canScale: true, // 图片是否允许滚轮播放
autoCrop: true, // 是否默认生成截图框 false
info: false, // 是否展示截图框信息
autoCropWidth: 200, // 生成截图框的宽度
autoCropHeight: 200, // 生成截图框的高度
canMoveBox: true, // 截图框是否可以拖动
fixedBox: true, // 固定截图框的大小
canMove: false, // 上传图片是否可拖动
centerBox: true, // 截图框限制在图片里面
},
2.5、这里cropper组件宽高默认父组件的宽高,父组件宽高这里是获取图片的宽高动态添加
watch: {
'option.img': {
handler: function (val) {
const that = this
const img = new Image()
img.src = val
img.onload = function () {
that.imgObj.width = this.width
that.imgObj.height = this.height
}
},
immediate: true
}
}
2.6、效果展示
3、实现截图框移动,下方自动预览截图框中的图片
3.1、添加预览图片元素
<img :src='previewImg' alt="" class='previewImg'>
3.2、data定义预览图片数据
previewImg: null, // 预览后的图片
3.3、@realTime 实时预览事件
在组件定义@realTime事件接收预览的数据
realTime (data) {
console.log(data)
const that = this
that.previewImg = data.url
}
3.3.1、下面的是打印的结果图片以及效果
3.3.2、但是当你移动截图框会发现下面预览的图片没有任何变化,看打印的data.url就会知道返回的url都是相同的,因为数据缓存,所以即使图片移动了也不会有任何变化
3.3.3、查询vue-cropper的内置方法
1 获取截图的 base64 数据:getCropData
this.$refs.cropper.getCropData(data => {
// do something
console.log(data)
})
2 获取截图的 blob 数据:getCropBlob
this.$refs.cropper.getCropBlob(data => {
// do something
console.log(data)
})
3.3.4、解决方法: 先用3.3.3中方法2实现实时预览中截图框移动图片更新
realTime (data) {
const that = this
this.$refs.cropper.getCropBlob(data => {
// 这里data数据为Blob类型,blobToDataURI方法转换成base64
this.blobToDataURI(data, function(res) {
that.previewImg = res
})
})
},
blobToDataURI(blob, callback) {
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onload = function (e) {
callback(e.target.result);
}
}
3.4、点击按钮获取当前截图框中的图片并下载(使用3.3.3中方法1)
3.4.1 添加元素
<el-button type='primary' @click='handleClick'>按钮</el-button>
<img :src="resImg" alt="" v-if="resImg" class='previewImg'>
3.4.2 data定义数据
resImg: null, //截图后图片
3.4.3、methods方法
handleClick () {
this.$refs.cropper.getCropData(data => {
console.log(data)
this.resImg = data
this.handleDownload(data)
})
},
handleDownload (url) {
var a = document.createElement("a"); // 生成一个a元素
var event = new MouseEvent("click"); // 创建一个单击事件
a.download = "photo"; // 设置图片名称, 这里可以自定义,也可以获取图片名称进行修改
a.href = url; // 将生成的URL设置为a.href属性
a.dispatchEvent(event); // 触发a的单击事件
}
3.4.4、打印结果以及效果
4、完整代码
```javascript
<template>
<div class="home">
<div class="cropper" :style='{width: `${imgObj.width}px`, height: `${imgObj.height}px`}'>
<vueCropper
ref="cropper"
:img="option.img"
:outputSize="option.outputSize"
:outputType="option.outputType"
:canScale='option.canScale'
:autoCrop='option.autoCrop'
:autoCropWidth='option.autoCropWidth'
:autoCropHeight='option.autoCropHeight'
:canMoveBox='option.canMoveBox'
:canMove='option.canMove'
:centerBox='option.centerBox'
:info='option.info'
:fixedBox='option.fixedBox'
@realTime='realTime'
></vueCropper>
</div>
<img :src='previewImg' alt="" class='previewImg' ref="img">
<el-button type='primary' @click='handleClick'>按钮</el-button>
<img :src="resImg" alt="" v-if="resImg" class='previewImg'>
</div>
</template>
<script>
import { VueCropper } from 'vue-cropper'
export default {
data () {
return {
option: {
img: require('../assets/preview.jpg'), // 裁剪图片地址
outputSize: 1, // 裁剪生成图片质量
outputType: 'jepg', // 裁剪生成图片格式
canScale: true, // 图片是否允许滚轮播放
autoCrop: true, // 是否默认生成截图框 false
info: false, // 是否展示截图框信息
autoCropWidth: 200, // 生成截图框的宽度
autoCropHeight: 200, // 生成截图框的高度
canMoveBox: true, // 截图框是否可以拖动
fixedBox: true, // 固定截图框的大小
canMove: false, // 上传图片是否可拖动
centerBox: true, // 截图框限制在图片里面
},
resImg: null, //截图后图片
previewImg: null, // 预览后的图片
previewObj: {
width: 200,
height: 200
},
imgObj: {
width: 500,
height: 500
}
}
},
components: {
VueCropper
},
watch: {
'option.img': {
handler: function (val) {
const that = this
const img = new Image()
img.src = val
img.onload = function () {
that.imgObj.width = this.width
that.imgObj.height = this.height
}
},
immediate: true
}
},
methods: {
handleClick () {
this.$refs.cropper.getCropData(data => {
console.log(data)
this.resImg = data
this.handleDownload(data)
})
},
handleDownload (url) {
var a = document.createElement("a"); // 生成一个a元素
var event = new MouseEvent("click"); // 创建一个单击事件
a.download = "photo"; // 设置图片名称, 这里可以自定义,也可以获取图片名称进行修改
a.href = url; // 将生成的URL设置为a.href属性
a.dispatchEvent(event); // 触发a的单击事件
},
realTime (data) {
const that = this
this.$refs.cropper.getCropBlob(data => {
// 这里data数据为Blob类型,blobToDataURI方法转换成base64
console.log(data)
this.blobToDataURI(data, function(res) {
console.log(res)
that.previewImg = res
})
})
},
blobToDataURI(blob, callback) {
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onload = function (e) {
callback(e.target.result);
}
},
},
mounted () {
}
}
</script>
<style lang="less" scoped>
@color: #333;
.home{
width: 100%;
height: 100%;
background-color: #eee;
.cropper{
width: 500px;
height: 500px;
border: 1px solid orange;
}
.previewImg{
width: 200Px;
height: 200Px;
object-fit: cover;
border-radius: 50%;
}
}
</style>
5、后续补充(2023-6-25)
因为新项目需求,需要模拟微信公众号封面图裁剪功能,需要支持两种尺寸在线剪切
5.1、option中img图片动态更换
因为是后端请求的网络图片,结果重新赋值后图片渲染不出来导致剪切板空白,后面通过转换base64后也不行,最后尝试blob发现可以实现,由于后端提供了转换base64的接口,这边就直接base64转换了二进制blob文件,转换方法在另一个博客里,也可以参照别的方法
链接:base64转blob
5.2、截图框尺寸比例固定
需要在option中添加如下代码
fixed: true,
fixedNumber: [2.35, 1],
或者参照文档提供的api做具体修改
5.3、仿照微信公众号提供两种尺寸在线修改
本来想做fixedNumber动态修改,但是对于不同尺寸切换和获取当前的图片有问题,所以创建了两个vueCropper来模拟两个固定尺寸来回切换,但是通过v-if去控制不同尺寸展示隐藏会有问题,所以这边使用了定位,当设置一个尺寸时,另一个尺寸的vueCropper中z-index=0则完美解决
效果图如下