利用vue-cropper做的关于图片裁剪、压缩、上传、预览等做的一个公共组件
程序员文章站
2022-04-08 16:07:07
...
利用vue-cropper做的关于图片裁剪、压缩、上传、预览等做的一个公共组件
<template>
<div>
<div class="upload-box">
<div class="image-box"
v-if="imageUrl"
:style="{'background-image': 'url('+ imageUrl +')', 'height': imageHeight}"></div>
<div class="upload">
<h6 class="upload-des">支持 jpg、png 格式大小 5M 以内的图片</h6>
<input type="file" @change="getFile" ref="file" id="file">
<label for="file">点击上传</label>
</div>
</div>
<!-- vueCropper 剪裁图片实现-->
<div class="vue-cropper-box" v-if="isShowCropper">
<div class="vue-cropper-content">
<vueCropper ref="cropper"
:img="option.img"
:outputSize="option.outputSize"
:outputType="option.outputType"
:info="option.info"
:canScale="option.canScale"
:autoCrop="option.autoCrop"
:autoCropWidth="option.autoCropWidth"
:autoCropHeight="option.autoCropHeight"
:fixed="option.fixed"
:fixedNumber="option.fixedNumber">
</vueCropper>
</div>
</div>
<el-button v-if="isShowCropper" type="danger" @click="onCubeImg">确定裁剪图片</el-button>
</div>
</template>
<script>
import VueCropper from "vue-cropper"
export default {
name: 'Avatar',
data () {
return {
//裁剪组件的基础配置option
option: {
img: '', //裁剪图片的地址
info: true, //裁剪框的大小信息
outputSize: 1, // 裁剪生成图片的质量
outputType: 'png', //裁剪生成图片的格式
canScale: false, // 图片是否允许滚轮缩放
autoCrop: true, // 是否默认生成截图框
autoCropWidth: 195, // 默认生成截图框宽度
autoCropHeight: 10, // 默认生成截图框高度
fixed: false, //是否开启截图框宽高固定比例
fixedNumber: [1, 1] //截图框的宽高比例
},
isShowCropper: false //是否显示截图框
}
},
props: {
// 特殊配置
cropperOption: {
type: Object,
default: () => {
return null
}
},
// 默认图片
imageUrl: {
type: String,
default: ''
},
// 图片展示高度
imageHeight: {
type: String,
default: '100px'
}
},
components: {
VueCropper
},
methods: {
getFile (e) {
let _this = this
var files = e.target.files[0]
if (!e || !window.FileReader) return // 看支持不支持FileReader
let reader = new FileReader()
reader.readAsDataURL(files)
reader.onloadend = function () {
_this.isShowCropper = true
_this.option.img = this.result
_this.$refs.file.value = ''
}
},
// 确定裁剪图片
onCubeImg () {
this.$refs.cropper.getCropData((data) => {
this.isShowCropper = false
//console.log("压缩前的图片大小:" + data.length)
let img = new Image(),
_this = this
img.src = data
img.onload = function() {
//let _data = _this.compress(img)
let blob = _this.dataURItoBlob(data)
let formData = new FormData()
formData.append("icon", blob)
//console.log("将blob对象转成formData对象:" + formData.get("icon"))
_this.$emit('cropped', data, formData)
}
})
},
// 压缩图片
compress(img) {
let canvas = document.createElement("canvas"),
ctx = canvas.getContext("2d"),
initSize = img.src.length,
width = img.width,
height = img.height;
canvas.width = width
canvas.height = height
// 铺底色
ctx.fillStyle = "#fff"
ctx.fillRect(0, 0, canvas.width, canvas.height)
ctx.drawImage(img, 0, 0, width, height)
//进行压缩
let ndata = canvas.toDataURL("image/jpeg", 0.8)
//console.log("压缩后的图片大小:" + ndata.length)
return ndata
},
// base64转成bolb对象
dataURItoBlob(base64Data) {
let byteString
if (base64Data.split(",")[0].indexOf("base64") >= 0)
byteString = atob(base64Data.split(",")[1])
else
byteString = unescape(base64Data.split(",")[1])
let mimeString = base64Data .split(",")[0] .split(":")[1] .split(";")[0];
let ia = new Uint8Array(byteString.length);
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], { type: mimeString })
},
// 初始化配置文件
initOptions () {
this.isShowCropper = false
if (this.cropperOption) {
for (let key in this.option) {
this.option[key] = this.cropperOption[key] || this.option[key]
}
}
}
},
created () {
this.initOptions()
}
}
</script>
<style scoped lang="stylus" rel="stylesheet">
.upload-box {
& > div {
display inline-block
vertical-align middle
}
& .upload-des {
margin 0
font-weight 400
color #909399
}
}
.image-box {
width 100px
height 100px
margin-right 20px
background-size 100px auto
background-position left center
background-repeat no-repeat
}
.upload {
& label {
width: 80px;
height: 24px;
font-size: 12px;
line-height: 24px;
display: inline-block;
border-radius: 4px;
text-align: center;
border: 1px solid #ddd;
cursor pointer
}
}
input[type='file'] {
display: none;
}
.vue-cropper-box {
width: 60%;
height: 200px;
margin: 15px 0px;
.vue-cropper-content {
height 200px
}
}
</style>
调用
<el-form-item label="头像" prop="icon" :rules="rules.required">
<Avatar v-on:cropped="doCrop"
:cropperOption="cropperOption"
:imageUrl="guestInfo.icon"></Avatar>
</el-form-item>
注意下面这个二进制文件接收和上传的问题
resetForm(){
this.$nextTick(() => {
this.$refs.guest.clearValidate()
this.guestUpInfo = new FormData()
})
},
//完成裁剪
doCrop(icon, file){
this.guestInfo.icon = icon
this.guestUpInfo = file
}
//新增、编辑提交
submitGuest(){
validCallback(this, 'guest', () => {
this.guestUpInfo.append('name',this.guestInfo.name)
this.guestUpInfo.append('position',this.guestInfo.position)
this.guestUpInfo.append('description',this.guestInfo.description)
if(this.guestInfo.seq){
this.guestUpInfo.append('seq',this.guestInfo.seq)
}
if(this.editGuest){
this.guestUpInfo.append('id',this.guestInfo.id)
}
publicSubmitApi('saveSpeaker', this.guestUpInfo, true).then(res => {
if (res.status === 200) {
this.guestShow = false
this.fetchData()
this.$message({
message: this.editGuest ? '编辑成功' : '新增成功',
type: 'success'
})
}
})
})
},
上一篇: python 动态传参
下一篇: celery + redis demo