需要实现的效果如下:
控制裁剪框的比例使用:
beforeRead(file, detail) {
if (detail.name == "changeSize1") {
this.option.fixedNumber = [522, 928];
} else if (detail.name == "changeSize2" || detail.name == "changeSize3") {
this.option.fixedNumber = [523, 453];
}
if (file.type !== "image/jpeg" && file.type !== "image/png") {
this.$toast("请上传 jpg/png 格式图片");
return false;
}
this.showCropper = true;
this.imageToBase64(file);
this.imageFileName = detail.name;
},
裁剪结束之后点击选择,上传服务器并回显:
getCropBlob() {
this.loadingShow = true;
this.$refs.cropper.getCropBlob((blob) => {
const url = URL.createObjectURL(blob);
const fileObject = {
url,
isImage: true,
file: blob,
};
if (this.imageFileName === "changeSize1") {
this.file1 = [fileObject];
} else if (this.imageFileName === "changeSize2") {
this.file2 = [fileObject];
} else if (this.imageFileName === "changeSize3") {
this.file3 = [fileObject];
}
this.showCropper = false;
this.loadingShow = false;
this.$emit("update:showAta", false);
});
},
完整代码如下:
<template>
<div class="photoAlbum">
<NavBar :title="title" />
<div class="content-box">
<van-uploader
v-model="file1"
class="uploader-left"
multiple
:max-count="1"
:before-read="beforeRead"
name="changeSize1"
/>
<div class="up-right">
<van-uploader
v-model="file2"
class="uploader-Tright"
multiple
:max-count="1"
:before-read="beforeRead"
name="changeSize2"
/>
<van-uploader
v-model="file3"
class="uploader-Bleft"
multiple
:max-count="1"
:before-read="beforeRead"
name="changeSize3"
/>
</div>
</div>
<div class="uploadava">
<van-popup
duration="0"
v-model="showCropper"
position="top"
:style="{ height: '100%' }"
>
<div class="cropper-container">
<van-loading
v-show="loadingShow"
size="50"
color="#fff"
vertical
text-color="#fff"
>上传中...</van-loading
>
<vueCropper
ref="cropper"
:img="option.img"
:outputSize="option.outputSize"
:outputType="option.outputType"
:info="option.info"
:full="option.full"
:autoCropWidth="option.autoCropWidth"
:autoCropHeight="option.autoCropHeight"
:canMove="option.canMove"
:canMoveBox="option.canMoveBox"
:original="option.original"
:autoCrop="option.autoCrop"
:fixed="option.fixed"
:fixedNumber="option.fixedNumber"
:centerBox="option.centerBox"
:infoTrue="option.infoTrue"
:fixedBox="option.fixedBox"
:high="option.high"
:mode="option.mode"
/>
<van-nav-bar
left-text="取消"
right-text="选择"
@click-left="onClickLeft"
@click-right="getCropBlob"
/>
</div>
</van-popup>
</div>
<!-- <div class="btn">
<button>确认</button>
</div> -->
</div>
</template>
<script>
import NavBar from "@/components/NavBar/NavBar";
import { Uploader } from "vant";
import { VueCropper } from "vue-cropper";
export default {
components: {
NavBar,
VueCropper,
},
props: {
showAta: {
default: false,
type: Boolean,
},
avaUrl: {
default: "",
type: String,
},
},
data() {
return {
title: "vcard.routes.photoAlbum",
file1: [],
file2: [],
file3: [],
show: true, // 上传类型的弹窗
imageFileName: "",
showCropper: false, // 裁剪的弹窗
option: {
img: "",
outputSize: 0.8,
info: false, // 裁剪框的大小信息
outputType: "jpeg", // 裁剪生成图片的格式
canScale: true, // 图片是否允许滚轮缩放
autoCrop: true, // 是否默认生成截图框
autoCropWidth: window.innerWidth - 100 + "px", // 默认生成截图框宽度
autoCropHeight: window.innerWidth - 100 + "px", // 默认生成截图框高度
high: true, // 是否按照设备的dpr 输出等比例图片
fixedBox: false, // 固定截图框大小 不允许改变
fixed: true, // 是否开启截图框宽高固定比例
fixedNumber: [], // 截图框的宽高比例
full: true, // 是否输出原图比例的截图
canMoveBox: true, // 截图框能否拖动
original: false, // 上传图片按照原始比例渲染
centerBox: true, // 截图框是否被限制在图片里面
infoTrue: false, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
mode: "100% auto", // 图片默认渲染方式
},
loadingShow: false, // 是否展示loading
};
},
methods: {
beforeRead(file, detail) {
if (detail.name == "changeSize1") {
this.option.fixedNumber = [522, 928];
} else if (detail.name == "changeSize2" || detail.name == "changeSize3") {
this.option.fixedNumber = [523, 453];
}
if (file.type !== "image/jpeg" && file.type !== "image/png") {
this.$toast("请上传 jpg/png 格式图片");
return false;
}
this.showCropper = true;
this.imageToBase64(file);
this.imageFileName = detail.name;
},
imageToBase64(file) {
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
this.option.img = reader.result;
};
},
getCropBlob() {
this.loadingShow = true;
this.$refs.cropper.getCropBlob((blob) => {
const url = URL.createObjectURL(blob);
const fileObject = {
url,
isImage: true,
file: blob,
};
if (this.imageFileName === "changeSize1") {
this.file1 = [fileObject];
} else if (this.imageFileName === "changeSize2") {
this.file2 = [fileObject];
} else if (this.imageFileName === "changeSize3") {
this.file3 = [fileObject];
}
this.showCropper = false;
this.loadingShow = false;
this.$emit("update:showAta", false);
});
},
onClickLeft() {
this.loadingShow = false;
this.showCropper = false;
this.$parent.showPhotoUploader = false;
},
},
};
</script>
<style scoped lang="scss">
@import "./photoAlbum.scss";
</style>
<style lang="scss">
.uploader-left {
width: 49%;
.van-uploader__wrapper {
width: 100%;
.van-uploader__upload {
width: 100%;
height: 5.96rem;
margin: 0;
}
}
.van-uploader__preview {
width: 100%;
margin: 0;
.van-image {
width: 100%;
height: 5.96rem;
}
}
}
.van-loading {
position: absolute;
z-index: 9999;
left: 50%;
top: 50%;
margin-left: -55px;
margin-top: -30px;
background: rgba(0, 0, 0, 0.3);
padding: 10px 30px;
border-radius: 25px;
}
.up-right {
width: 49%;
position: relative;
height: 5.96rem;
.van-uploader {
width: 100%;
.van-uploader__wrapper {
width: 100%;
.van-uploader__upload {
width: 100%;
height: 2.9rem;
margin: 0;
}
}
}
.uploader-Bleft {
position: absolute;
bottom: 0;
right: 0;
}
.van-uploader__preview {
width: 100%;
margin: 0;
.van-image {
width: 100%;
height: 2.9rem;
}
}
}
.uploadava {
.update-avatar {
height: 100%;
text-align: center;
.update-avatar-line {
width: 100%;
height: 1px;
background-color: #979797;
}
.avatar-select-type {
background-color: #fff;
width: 346px;
border-radius: 12px;
padding-bottom: 4px;
.upload-avator {
padding: 14px;
}
}
p {
margin: 15px 0 30px;
background-color: #fff;
width: 346px;
border-radius: 12px;
padding: 15px 0 18px;
}
}
.cropper-container {
height: 90.7vh;
.van-nav-bar {
background-color: rgba(0, 0, 0, 0.87);
:global(.van-nav-bar__text) {
color: #fff;
}
:global(.van-nav-bar__text:nth-child(2)) {
color: #000;
font-weight: 500;
}
}
}
.vue-cropper {
background: #000;
height: 100%;
padding-top: 46px;
box-sizing: border-box;
}
}
</style>