<!-- * 图片裁剪 --> <script setup lang="ts"> import { ref, reactive } from 'vue'; import { VueCropper } from 'vue-cropper'; import { useMessage } from 'src/common/hooks'; defineExpose({ openModel, }); const emit = defineEmits<{ (e: 'onOk', value: any): void; }>(); const { warn } = useMessage(); const cropperRef = ref<any>(null); const show = ref(false); const previewStyle1 = ref({}); const previews = ref<any>({ div: '', url: '', img: '', }); const option = reactive({ img: '', }); function openModel() { show.value = true; } function onClose() { show.value = false; previewStyle1.value = {}; previews.value = { div: '', url: '', img: '', }; option.img = ''; } // 实时预览 function realTime(data: any) { previews.value = data; previewStyle1.value = { width: previews.value.w + 'px', height: previews.value.h + 'px', overflow: 'hidden', margin: '0', zoom: 140 / previews.value.w, }; } // 提交 function uploadImg() { if (option.img) { // 获取截图的 base64 数据 cropperRef.value.getCropData((data: any) => { emit('onOk', data); onClose(); }); } else { warn('请选择图片'); } } // 选择上传图片 function selectImg() { let _input: HTMLInputElement = document.createElement('input'); _input.setAttribute('type', 'file'); _input.setAttribute('accept', 'image/*'); // 上传类型 _input.onchange = function (e: any) { let myFiles = e.target.files; let myFile = myFiles[0]; //准备读取图片 if (window.FileReader && myFile) { // 调用图片读取方法 let reader = new FileReader(); // 读取图片 reader.readAsDataURL(myFile); // 监听图片读取进度 reader.onloadend = function (e: any) { // 读取成功,拿到base64编码 let imgBase64 = e.target.result; option.img = imgBase64; }; } }; _input.click(); } </script> <template> <q-dialog v-model="show" persistent> <q-card style="width: 700px; max-width: 700px"> <q-card-section class="row items-center q-pb-none"> <div class="text-h6">上传头像</div> <q-space /> <q-btn icon="close" flat round dense v-close-popup @click="onClose" /> </q-card-section> <q-card-section style="padding-bottom: 8px"> <div class="content" style="height: 400px; width: 100%"> <div class="left content-item"> <div class="left-content"> <VueCropper ref="cropperRef" :img="option.img" autoCrop fixed @realTime="realTime" ></VueCropper> </div> <div class="left-action"> <q-btn color="primary" label="上传" outline icon="cloud_upload" @click="selectImg" /> </div> </div> <div class="right content-item"> <div class="right-content"> <div class="previews-box"> <div :style="previewStyle1"> <div :style="previews.div"> <img :src="previews.url" :style="previews.img" /> </div> </div> </div> </div> <div class="right-action"> <q-btn color="primary" label="提交" unelevated @click="uploadImg" /> </div> </div> </div> </q-card-section> </q-card> </q-dialog> </template> <style lang="scss" scoped> .content { display: grid; grid-template-columns: 1fr 1fr; } .left { // background-color: pink; } .right { // background-color: bisque; } .right-content { display: flex; align-items: center; justify-content: center; // > img { // width: 140px; // height: 140px; // object-fit: contain; // border: 1px solid rgba(180, 180, 180, 0.3); // border-radius: 50%; // } .previews-box { box-sizing: border-box; overflow: hidden; width: 140px; height: 140px; border: 1px solid rgba(180, 180, 180, 0.3); border-radius: 50%; } } .right-action { display: flex; align-items: center; justify-content: center; } .left-action { display: flex; align-items: center; } .content-item { display: grid; grid-template-rows: auto 70px; } </style>