<template> <div class="avatar-container"> <el-dialog :title="title" :model-value="dialogVisibleCorpper" width="800px" append-to-body @opened="openDialog" :before-close="beforeClose"> <el-row> <el-col :span="12" style="height: 300px"> <vue-cropper ref="cropper" :img="options.img" :info="true" :autoCrop="options.autoCrop" :autoCropWidth="options.autoCropWidth" :autoCropHeight="options.autoCropHeight" :canMove="options.canMove" :fixedBox="options.fixedBox" :outputType="options.outputType" @realTime="realTime" :fixed="options.fixed" v-if="showCropper" /> </el-col> <el-col :span="12" style="height: 300px"> <div class="preview-box"> <img v-if="previews.url" :src="previews.url" :style="previews.img" /> <span v-else></span> </div> </el-col> </el-row> <el-row style="margin-top: 12px"> <el-col :span="12"> <el-row> <el-col :span="8"> <el-upload action="#" :http-request="() => { }" :before-upload="beforeUpload" :show-file-list="false"> <el-button>选择</el-button> </el-upload> </el-col> <el-col :span="4"> <el-button :icon="Plus" @click="changeScale(1)"></el-button> </el-col> <el-col :span="4"> <el-button :icon="Minus" @click="changeScale(-1)"></el-button> </el-col> <el-col :span="4"> <el-button :icon="RefreshLeft" @click="rotateLeft()"></el-button> </el-col> <el-col :span="4"> <el-button :icon="RefreshRight" @click="rotateRight()"></el-button> </el-col> </el-row> </el-col> <el-col :span="4" :offset="8" style="margin-left: 22.3%"> <el-button type="primary" @click="determine()">提 交</el-button> </el-col> </el-row> </el-dialog> </div> </template> <script setup lang="ts"> import { Plus, Minus, RefreshLeft, RefreshRight, } from "@element-plus/icons-vue"; import { ElMessage } from "element-plus"; import "vue-cropper/dist/index.css"; import { upLoadFile } from "@/api/api"; import { VueCropper } from "vue-cropper"; import { getCurrentInstance, ref, reactive, watch } from "vue"; const { proxy } = getCurrentInstance() as any; const props = defineProps({ dialogVisibleCorpper: { type: Boolean, default: false, }, title: { type: String, default: "上传图片", }, }); const cropper: any = ref(VueCropper) const showCropper = ref(false); // cropper配置 更多配置可参考 https://www.npmjs.com/package/vue-cropper const options: any = reactive({ img: null, // 裁剪图片的地址 autoCropWidth: 200, // 默认生成截图框宽度 默认容器的 80% autoCropHeight: 200, // 默认生成截图框高度 默认容器的 80% fixed:true, outputType: "png", // 裁剪生成图片的格式 jpeg, png, webp autoCrop: true, // 是否默认生成截图框 fixedBox: false, // 固定截图框大小 canMove:false, // centerBox:true, }); const filePath = ref(''); const previews: any = ref({ url: "", }); // 打开裁剪弹窗 const openDialog = () => { showCropper.value = true; }; // 修改图片大小 正数为变大 负数变小 const changeScale = (num: any) => { num = num || 1; proxy.$refs.cropper.changeScale(num); }; // 向左边旋转90度 const rotateLeft = () => { proxy.$refs.cropper.rotateLeft(); }; // 向右边旋转90度 const rotateRight = () => { proxy.$refs.cropper.rotateRight(); }; // 上传图片处理 const beforeUpload = (rawFile: any) => { if (rawFile.type.indexOf("image/") == -1) { ElMessage.error("请上传图片类型文件!"); return false; } if (rawFile.size / 1024 / 1024 > 2) { ElMessage.error("文件大小不能超过2MB!"); return false; } const reader = new FileReader(); reader.readAsDataURL(rawFile); reader.onload = () => { // 图片在这里 options.img = reader.result; console.log(options) }; }; // 实时预览事件 const realTime = (data: any) => { previews.value = data; console.log(previews.value) }; const emit = defineEmits(["update:dialogVisibleCorpper", "confirm"]); // 关闭弹窗 const beforeClose = () => { options.img = null; previews.value.url = ""; emit("update:dialogVisibleCorpper", false); }; // 提交图片 const determine = () => { // console.log(options.img) // options.img = null; // previews.value.url = ""; // emit("confirm"); cropper.value.getCropBlob(async (data: any) => { const imgUrl = window.URL.createObjectURL(data); const response = await fetch(imgUrl); const blobData = await response.blob(); console.log(blobData) const formData = new FormData(); formData.append('icon', blobData, 'filename.png'); upLoadFile(formData).then((res:any) => { console.log(res) filePath.value = res.file_path; options.img = null; previews.value.url = ""; emit("confirm", filePath.value); console.log(filePath.value) }) // imageUpload(formData).then(res => { // isLoading.value = false // show.value = false // props.getPropsUrl(res.data.data.url) // }); }) }; </script> <style lang="scss" scoped> .avatar-container { .img-box { border-radius: 50%; border: 1px solid #ccc; width: 10vw; height: 10vw; } } .preview-box { position: absolute; top: 50%; transform: translate(50%, -50%); width: 200px; height: 200px; border-radius: 50%; border: 1px solid #ccc; overflow: hidden; } </style>