Vue学习笔记:vue-cropper实现封装截图组件
vue-cropper一款好用的前端截图插件项目介绍:使用vue+elementUI写的项目,需要用到图片截图功能、视频截图、视频直播等功能,关于截图不失真,发现vue-cropper这款插件能满足需求,可以让用户自由调整截图框的宽高、位置,可以根据用户的需求选择截图的格式(png、jpg),也可以选择图片的编码格式(base64、blob)等。案例展示:http://zhb_nyx.gitee.
·
-
vue-cropper一款好用的前端截图插件
项目介绍:
使用vue+elementUI写的项目,需要用到图片截图功能、视频截图、视频直播等功能,关于截图不失真,发现vue-cropper这款插件能满足需求,可以让用户自由调整截图框的宽高、位置,可以根据用户的需求选择截图的格式(png、jpg),也可以选择图片的编码格式(base64、blob)等。
案例展示:
http://zhb_nyx.gitee.io/cropperimg/#/cropperImg
官方网站:
https://github.com/xyxiao001/vue-cropper
组件文档:
第一步:项目中引入vue-cropper插件
npm install vue-cropper --save 或者 npm install vue-cropper -S
第二步:引入依赖,
在main.js中引入
import VueCropper from 'vue-cropper'
Vue.use(VueCropper)
按需引入
import VueCropper from 'vue-cropper'
第三步:封装弹框内截图组件
如上图样式布局,
<template>
<div class="imgCrop-body">
<!--图片显示区域-->
<div class="imgCrop-box">
<!--原图-->
<div class="imgCrop-con">
<vue-cropper
ref="cropper"
:img="option.img"
:output-size="option.size"
:output-type="option.outputType"
:info="true"
:full="option.full"
:fixed="fixed"
:fixed-number="fixedNumber"
:can-move="option.canMove"
:can-move-box="option.canMoveBox"
:fixed-box="option.fixedBox"
:original="option.original"
:auto-crop="option.autoCrop"
:auto-crop-width="option.autoCropWidth"
:auto-crop-height="option.autoCropHeight"
:center-box="option.centerBox"
@real-time="realTime"
:high="option.high"
@img-load="imgLoad"
mode="cover">
</vue-cropper>
</div>
<!--截图-->
<div class="imgCrop-con imgCrop-con-preview" ref="imgCropPreviews">
<div class="show-preview" :style="{'width': previews.w + 'px', 'height': previews.h + 'px', 'overflow': 'hidden', 'margin': '5px'}">
<div :style="previews.div">
<img :src="previews.url" :style="previews.img">
</div>
</div>
</div>
</div>
<!--操作区域-->
<div class="imgCrop-btn">
<div class="ict-query-button">
<label for="uploads" style="width:100%;height: 100%; ">上传</label>
<input
type="file"
id="uploads"
style="position:absolute; clip:rect(0 0 0 0);"
ref="uploadImg"
accept="image/png, image/jpeg, image/gif, image/jpg"
@change="uploadImg($event, 1)"
>
</div>
<div class="ict-query-button" v-if="!crap" @click="startCrop">截取</div>
<div class="ict-query-button" v-else @click="stopCropAndSave">保存</div>
<div class="ict-query-button" @click="changeScale(100)">放大</div>
<div class="ict-query-button" @click="changeScale(-100)">缩小</div>
<div class="ict-query-button" @click="clearCrop">清空</div>
<div class="ict-query-button" @click="refreshCrop">刷新</div>
<div class="ict-query-button" @click="rotateLeft">向右旋转90度</div>
<div class="ict-query-button" @click="rotateRight">向左旋转90度</div>
</div>
</div>
<!--到底啦!=======================================================-->
</template>
<script>
export default {
name: "cropperImgComponents",
data(){
return {
crap: true,
previews: {},
option: {
// 裁剪图片的地址
img: '',
// 裁剪生成图片的质量
size: 1,
// 输出原图比例截图 props名full
full: false,
// 裁剪生成图片的格式
outputType: 'png',
// 上传图片是否可以移动
canMove: true,
// 固定截图框大小 不允许改变
fixedBox: false,
// 上传图片按照原始比例渲染
original: false,
// 截图框能否拖动
canMoveBox: true,
// 是否默认生成截图框
autoCrop: true,
// 只有自动截图开启 宽度高度才生效
// 默认生成截图框宽度
autoCropWidth: 400,
// 默认生成截图框高度
autoCropHeight: 350,
// 截图框是否被限制在图片里面
centerBox: false,
// 是否按照设备的dpr 输出等比例图片
high: true
},
show: true,
// 是否开启截图框宽高固定比例
fixed: false,
// 截图框的宽高比例
fixedNumber: [1, 2],
// 裁剪框的大小信息
info: true,
// canScale 图片是否允许滚轮缩放
canScale: true,
// infoTrue true 为展示真实输出图片宽高 false 展示看到的截图框宽高:
infoTrue: true,
// maxImgSize 限制图片最大宽度和高度
maxImgSize: 2000,
// enlarge 图片根据截图框输出比例倍数
enlarge: 1,
// mode 图片默认渲染方式
mode: 'contain'
}
},
mounted() {
},
methods:{
setCropImg(){
this.$refs.uploadImg.click()
this.crap = true
},
//上传图片
uploadImg(e, num) {
var file = e.target.files[0]
this.file = file
console.log(file);
if (file.size / 1024 / 1024 > 5) {
this.$message.info("上传文件不超过5M");
return;
}
if (!/\.(jpg|png|JPG|PNG)$/.test(file.name)) {
this.$message.info('图片类型必须是jpg,png中的一种')
return false
}
var reader = new FileReader()
reader.onload = (e) => {
let data
if (typeof e.target.result === 'object') {
// 把Array Buffer转化为blob 如果是base64不需要
data = window.URL.createObjectURL(new Blob([e.target.result]))
} else {
data = e.target.result
}
if (num === 1) {
this.option.img = data
} else if (num === 2) {
this.example2.img = data
}
}
// 转化为base64
// reader.readAsDataURL(file)
// 转化为blob
reader.readAsArrayBuffer(file)
},
imgLoad(msg) {
console.log(msg)
this.previews.url = msg.url
},
// 实时预览函数
realTime(data) {
this.previews = data
this.$emit('', this.previews)
console.log(data)
},
//开始截图
startCrop() {
this.crap = true
this.$refs.cropper.startCrop()
},
//停止截图&保存
stopCropAndSave() {
this.crap = false
this.$refs.cropper.stopCrop()
this.$refs.cropper.getCropData((data) => {
this.base64ToFile(data,'cropFile')
})
},
//清空截图
clearCrop() {
this.$refs.cropper.clearCrop()
this.crap = false
},
//放大缩小
changeScale(num) {
num = num || 1
this.$refs.cropper.changeScale(num)
},
//刷新
refreshCrop() {
this.$refs.cropper.refresh()
this.crap = false
},
//向左旋转
rotateLeft() {
this.$refs.cropper.rotateLeft()
},
//向右旋转
rotateRight() {
this.$refs.cropper.rotateRight()
},
//base64ToFile
base64ToFile(urlData, fileName) {
var arr = urlData.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
let imgFile = new File([u8arr], fileName, {type:mime});
this.$parent.getCropApi(imgFile,urlData)
},
}
}
</script>
<style lang="scss" scoped>
.imgCrop-body{
width: 100%;
height: 100%;
overflow: hidden;
//图片显示区域
.imgCrop-box{
width: 100%;
height: calc(100% - 100px);
display: flex;
justify-content: center;
align-items: center;
.imgCrop-con{
width: calc(50% - 20px);
height: calc(100% - 20px);
margin: 10px;
&.imgCrop-con-preview{
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMzTjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC");
}
}
}
//操作区域
.imgCrop-btn{
width: 100%;
height: 50px;
margin-top: 20px;
display: flex;
justify-content: center;
>div{
margin: 0 10px;
}
}
}
</style>
第四步:封装点击打开文件上传,弹出截取图片
<template>
<div class="upfile">
<div class="addFile" v-if="isAddFile" @click="getCropImg">+</div>
<div v-else class="addFileImg" @click="getCropImg">
<img :src="imgBase64">
</div>
<!--截图区域-->
<div class="CropDialogVisible" v-show="isCropDialogVisible">
<div class="CropDialog-main" style="height: 80vh;position: relative;">
<div class="CropDialog-close" @click="isCropDialogVisible = false">×</div>
<cropper-img ref="cropImg"></cropper-img>
</div>
</div>
</div>
</template>
<script>
import cropperImg from './cropperImg.vue'
export default {
name: "upfile",
props: ["type","imgUrl"],
created() {
console.log(this.imgUrl);
if(this.imgUrl){
this.imgBase64 = this.imgUrl
this.filedisabled = false
}
},
data() {
return {
imgBase64:'',
//
isCropDialogVisible:false,
cropFile:'',
isAddFile:true
};
},
components:{
cropperImg
},
methods: {
getCropImg(){
let that = this
this.$refs.cropImg.setCropImg()
setTimeout(function () {
that.isCropDialogVisible = true
},500)
},
getCropApi(file,base64){
console.log(file, base64);
this.imgBase64 = base64
this.isCropDialogVisible = false
this.isAddFile = false
this.$emit("getCropFile",{File:file,Base64:base64})
}
}
};
</script>
<style lang="scss" scoped>
.CropDialogVisible{
width: 100%;
height: 100%;
position: fixed;
top:0;
left: 0;
background: rgba(0,0,0,.4);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
.CropDialog-main{
width: 80%;
height: 80%;
background: #ffffff;
.CropDialog-close{
width: 40px;
height: 40px;
background: #666666;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
position: absolute;
top: -12px;
right: -20px;
font-size: 38px;
cursor: pointer;
}
}
}
.upfile{
width: 200px;
.addFileImg{
display: block;
width: 80px;
height: 80px;
background: #eeeeee;
cursor: pointer;
img{
display: block;
width: 100%;
height: 100%;
}
}
.addFile{
width: 80px;
height: 80px;
border: 1px dotted #64686B;
border-radius:4px;
font-size: 35px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
color:#64686B;
}
}
.avatar-file {
text-align: center;
}
.avatar-file-text {
width: 240px;
border: 1px solid #dddddd;
border-radius:3px;
line-height: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
font-weight: 500;
font-size: 14px;
white-space: nowrap;
padding: 0 5px;
cursor: pointer;
border-radius:0;
}
.avatar-file-text img {
width: 16px;
height: 16px;
margin-right: 9px;
}
.avatar-file-imgbox {
height: 65px;
display: flex;
align-items: center;
justify-content: flex-start;
border: 1px solid#C0C4CC;
}
.filename {
font-size: 14px;
font-weight: 400;
text-decoration: underline;
text-align: left;
color: #1d73f6;
line-height: 22px;
margin-left: 10px;
}
.filename span {
width: 8px;
height: 8px;
// color: #ff0000;
font-size: 36px;
cursor: pointer;
}
</style>
第五步:调用截取图片组件
<template>
<div style="width: 100%;display: flex;align-items: center;justify-content: center;">
<div style="display: flex;align-items: center">
<span style="margin-right: 20px;">截取图片</span>
<cropper-file></cropper-file>
</div>
</div>
</template>
<script>
import cropperFile from './cropperFile.vue'
export default {
name: "cropper",
data(){
},
methods:{
},
components:{
cropperFile
}
}
</script>
<style scoped>
</style>
现已将该功能整合进我的UI组件库内,大家可以前往下载使用;
文档如上;
最后
热爱分享!乐于助人!
大家好,我是“前端互助会”,欢迎大家关注微信公众号“前端公众号”!
一起学习,共同成长!
更多推荐
已为社区贡献9条内容
所有评论(0)