vue-cropper实现图片裁剪上传
程序员文章站
2022-04-09 09:14:06
...
1.图片裁剪组件photoCut.vue
<template>
<div>
<div class="info-item">
<div class="line">
<div class="cropper-content">
<div class="cropper" style="text-align: center">
<div v-show="!option.img" class="uploadimg">
<div style=" padding-top: 20px;">
<i class="ic-upload-cloud iconfont"/>
</div>
<div style="line-height:22px;color:#79818B;margin-top: -33px">
支持jpg、png格式的图片,大小不超过2M
</div>
<div style="margin-top: 30px">
<Button class="but" @click="newUpload">上传图片</Button>
<input type="file" id="uploads" :value="imgFile" style="position:absolute; clip:rect(0 0 0 0);"
accept="image/png, image/jpeg,image/jpg" @change="uploadImg($event, 1)">
</div>
</div>
<vueCropper
v-show="option.img"
ref="cropper"
:img="option.img"
:outputSize="option.size"
:outputType="option.outputType"
:info="option.info"
:full="option.full"
:canMove="option.canMove"
:canMoveBox="option.canMoveBox"
:canScale="option.canScale"
:original="option.original"
:autoCrop="option.autoCrop"
:autoCropWidth="option.autoCropWidth"
:autoCropHeight="option.autoCropHeight"
:fixedBox="option.fixedBox"
:centerBox="option.centerBox"
:enlarge="option.enlarge"
:mode="option.mode"
@realTime="realTime"
@imgLoad="imgLoad"
></vueCropper>
</div>
<div class="yulanimg" style="position: relative">
<div v-show="option.img">
<div class="show-preview" :style="previewStyle1" style="top: -63px;left: -60px;">
<div :style="previews.div" class="preview">
<img v-show="option.img" :src="previews.url" :style="previews.img">
</div>
</div>
<div class="show-preview" :style="previewStyle2" style="top: 29px;left: -60px;">
<div :style="previews.div" class="preview">
<img v-show="option.img" :src="previews.url" :style="previews.img">
</div>
</div>
<div class="show-preview" :style="previewStyle3" style="top: 100px;left: -60px;">
<div :style="previews.div" class="preview">
<img v-show="option.img" :src="previews.url" :style="previews.img">
</div>
</div>
</div>
<div v-show="!option.img">
<div class="imgdiv1">
</div>
<div class="imgdiv2">
</div>
<div class="imgdiv3">
</div>
</div>
<div class="show-preview"
style="height: 40px;width: 100%;
top: 296px;
left: 0px;">
<Button class="but" v-show="option.img" @click="newUpload">重新上传</Button>
<div v-show="!option.img" style="font-size:12px;
line-height:22px;
color:rgba(139,148,165,1);">预览
</div>
</div>
</div>
</div>
</div>
<!--<input type="button" class="btn btn-blue" value="上传头像" @click="finish('blob')">-->
</div>
<div flex="main:center" style="margin: 30px 0px 0px;">
<Button @click="cancel" class=" resetBtn" size="large" style="width: 76px">取消</Button>
<Button @click="finish('blob')" :loading="buttonLoading" type="primary" size="large" style="width: 76px">保存</Button>
</div>
</div>
</template>
<script>
import {VueCropper} from 'vue-cropper'
import {Button, Icon} from "view-design"
import {uploadImg} from './api/index'
export default {
data() {
return {
buttonLoading:false,
previewStyle1: {},
previewStyle2: {},
previewStyle3: {},
headImg: '',
//剪切图片上传
crap: false,
previews: {},
option: {
img: '',//裁剪图片的地址
outputSize: 1, //剪切后的图片质量(0.1-1)
outputType: 'png',//裁剪生成图片的格式
info: true,//裁剪框的大小信息
canScale: true,//图片是否允许滚轮缩放
autoCrop: true,//是否默认生成截图框
autoCropWidth: 250,//默认生成截图框宽度
autoCropHeight: 250,//默认生成截图框高度
//fixed 是否开启截图框宽高固定比例true
//fixedNumber 截图框的宽高比例
full: false,//输出原图比例截图 false
fixedBox: true,//固定截图框大小 不允许改变
canMove: true,//上传图片是否可以移动
canMoveBox: false,//截图框能否拖动
original: false,//上传图片按照原始比例渲染
centerBox: false,// centerBox 截图框是否被限制在图片里面
// high 是否按照设备的dpr 输出等比例图片
infoTrue: true, // 为展示真实输出图片宽高 false 展示看到的截图框宽高
// maxImgSize 限制图片最大宽度和高度
enlarge: 0.5, //图片根据截图框输出比例倍数
mode: 'contain' //图片默认渲染方式
},
fileName: '', //本机文件地址
//downImg: '#',
imgFile: '',
//uploadImgRelaPath: '', //上传后的图片的地址(不带服务器域名)
}
},
components: {
VueCropper, Button, Icon
},
methods: {
newUpload() {
document.getElementById("uploads").click()
},
//上传图片(点击上传按钮)
finish(type) {
this.buttonLoading=true
if (!this.fileName) {
this.buttonLoading=false
this.$Message.info("请上传logo!")
return
}
if (type === 'blob') {
// 获取截图的blob数据
this.$refs.cropper.getCropBlob((data) => {
// let img = window.URL.createObjectURL(data)
// this.model = true;
// this.modelSrc = img;
//裁剪后的图片显示
// this.option.img = this.modelSrc;
var forms = new FormData()
forms.append('file', data)
uploadImg(forms).then(res=>{
this.buttonLoading=false
if (res.status == 200) {
// this.$Message.success(res.message)
this.$emit("uploaderSuccess", res.data.filePath)
this.cancel()
} else {
this.$Message.error(res.message)
}
}).catch(res=>{
this.buttonLoading=false
this.$Message.error(res.message)
})
// axios.post(
// "/bnd-admin/v1/file/uploadImage",
// forms,
// {
// headers: {
// 'Authorization': 'eyJ2ZXIiOiIxLjAiLCJ0eXAiOiIxIiwiZXB0IjoyLCJraWQiOiJlMDhhYzY2Mi02YWU2LTRiZjktYjlmNS1kYzdmZTMxZTdlMjQiLCJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJVQUFDIiwiaWF0IjoxNTc5MDcyNTk3LCJuYmYiOjE1NzkwNzI1OTcsImF1ZCI6IldFQiIsInN1YiI6Ik5Eb2xSVFlsUWpFbFFVRWxSVFlsUWpRbE9FSXgifQ.AJrhGLNeHj1Csl-3FmkdnaahbLP2QveXkFVfr6GmV3IdFfLBXBK2_G8qn5_ljU_XqWAf5s0Pul1IcgOvzT4WKtuuAOS6bL_GVOEyiVu_oXmqhXxJfUt00FkIeUfEP3IwBEVK9cbYmhrc0a68bnLCEjGUbpj6gocPheZKzAM0XlxXZCob',
// 'Content-Type': 'multipart/form-data'
// }
// }
// ).then(res => {
// if (res.data.status == 200) {
// console.log(res)
// // this.$Message.success("上传成功")
// // this.$emit("uploaderSuccess", res.data.data.filePath)
// // this.cancel()
// } else {
// this.$Message.error("上传失败1")
// }
//
// }).catch(res => {
// this.$Message.error("上传失败2")
// });
})
} else {
// 获取截图的base64 数据
this.$refs.cropper.getCropData((data) => {
this.model = true;
this.modelSrc = data;
})
}
},
// 实时预览函数
realTime(data) {
var previews = data;
this.previewStyle1 = {
width: previews.w + "px",
height: previews.h + "px",
overflow: "hidden",
margin: "0",
transform: `scale(${80 / previews.w})`
};
this.previewStyle2 = {
width: previews.w + "px",
height: previews.h + "px",
overflow: "hidden",
margin: "0",
transform: `scale(${60 / previews.w})`
};
//固定为40宽度
this.previewStyle3 = {
width: previews.w + "px",
height: previews.h + "px",
overflow: "hidden",
margin: "0",
transform: `scale(${40 / previews.w})`
// zoom: 40 / previews.w
};
this.previews = data
},
cancel() {
this.$emit("cnacelModal")
},
//选择本地图片
uploadImg(e, num) {
console.log('uploadImg',e.target.value);
var _this = this;
//上传图片
var file = e.target.files[0]
_this.fileName = file.name;
if (!/\.(jpeg|jpg|png)$/.test(e.target.value)) {
e.target.value=''
this.$Message.info("只支持jpg、png、jpeg格式图片!")
return
}
if (file.size / 1024 / 1024 > 2) {
e.target.value=''
this.$Message.info("图片不得大于2M!")
return
}
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('imgLoad')
console.log(msg)
}
},
}
</script>
<style scoped lang="less">
/deep/ .ivu-btn > .ivu-icon {
width: 14px;
height: 14px;
line-height: 1;
}
.resetBtn{
margin-right: 16px;
background:rgba(240,242,245,1);
border: 1px solid rgba(240,242,245,1);
color: #363A40;
}
.resetBtn:hover{
background: #E5E6E8;
}
.ic-upload-cloud{
color:#CDD6E1;
font-size: 112px;
}
/deep/ .cropper-view-box {
outline: 1px dashed white;
}
/deep/ span.cropper-view-box {
margin-bottom: 16px;
}
/deep/ div.cropper-crop-box:after {
content: '鼠标滚轮缩放图片大小,鼠标拖拽调整图片位置';
color: white;
font-size: 12px;
white-space: nowrap;
margin-top: 16px;
}
/deep/ .crop-info {
display: none;
}
/deep/ .vue-cropper {
background-image: none;
}
.but {
color: #4183FA;
border-color: white
}
.but:hover {
background: #3473E7;
color: white;
}
.uploadimg {
width: 350px;
height: 350px;
background: rgba(248, 250, 255, 1);
opacity: 1;
}
.yulanimg {
margin-left: 2px;
width: 128px;
height: 350px;
background: rgba(248, 250, 255, 1);
opacity: 1;
}
.imgdiv1 {
width: 80px;
height: 80px;
background: #DDDFE8;
border-radius: 50%;
border: 2px solid white;
margin: 21px 0px 0px 25px;
}
.imgdiv2 {
width: 60px;
height: 60px;
background: #DDDFE8;
border-radius: 50%;
border: 2px solid white;
margin: 23px 0px 0px 34px;
}
.imgdiv3 {
width: 40px;
height: 40px;
background: #DDDFE8;
border-radius: 50%;
border: 2px solid white;
margin: 20px 0px 0px 45px;
}
.info {
width: 720px;
margin: 0 auto;
.oper-dv {
height: 20px;
text-align: right;
margin-right: 100px;
a {
font-weight: 500;
&:last-child {
margin-left: 30px;
}
}
}
.info-item {
margin-top: 15px;
label {
display: inline-block;
width: 100px;
text-align: right;
}
.sel-img-dv {
position: relative;
.sel-file {
position: absolute;
width: 90px;
height: 30px;
opacity: 0;
cursor: pointer;
z-index: 2;
}
.sel-btn {
position: absolute;
cursor: pointer;
z-index: 1;
}
}
}
}
.cropper-content {
display: flex;
display: -webkit-flex;
justify-content: flex-end;
-webkit-justify-content: flex-end;
.cropper {
width: 350px;
height: 350px;
}
.show-preview {
width: 250px;
height: 250px;
position: absolute;
flex: 1;
-webkit-flex: 1;
display: flex;
display: -webkit-flex;
justify-content: center;
-webkit-justify-content: center;
.preview {
overflow: hidden;
border-radius: 50%;
border: 6px solid white;
background: #DDDFE8;
margin-left: 40px;
}
}
}
.cropper-content .show-preview .preview {
margin-left: 0;
}
</style>
2.图片上传接口index.js文件
import axios from "axios"
const $postImg = (url, data) => {
return axios({
method: 'post',
url,
data,
headers: { 'Content-Type': 'multipart/form-data' }
})
}
export const uploadImg = (obj) => {
return $postImg('图片上传路径', obj)
}