效果图
上传图片弹窗预览
对于这个上传图片样式可以参考
官方原代码
官网传送入口 Upload 上传 | Element Plus (element-plus.org)
<template>
<el-upload
class="upload-demo"
drag
action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
multiple
>
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">
Drop file here or <em>click to upload</em>
</div>
<template #tip>
<div class="el-upload__tip">
jpg/png files with a size less than 500kb
</div>
</template>
</el-upload>
</template>
<script setup lang="ts">
import { UploadFilled } from '@element-plus/icons-vue'
</script>
上传图片之后
裁剪图片之后
预览视频
裁剪图片预览视频
操作步骤
安装依赖
npm install cropperjs
npm i qs
npm i axios
npm i element-plus
template部分
<template>
<div>
<el-dialog :title="dialogTitle.imgTitle" width="800px" v-model="dialogVisible.imgCropperVisible" :before-close="handleBeforeClose">
<div v-if="imageSrc" style="display: flex; justify-content: space-between; align-items: center;">
<!-- Display cropped image or original image if not cropped with background -->
<div style="width: 50%; padding: 10px; background-color: #f5f5f5; display: flex; justify-content: center; align-items: center;">
<img ref="previewImage" :src="croppedImageSrc || imageSrc" alt="Preview Image" style="max-width: 100%; height: auto;" />
</div>
<!-- Upload image section without background -->
<div style="width: 50%; padding: 10px; display: flex; justify-content: center; align-items: center;">
<img ref="uploadImage" :src="imageSrc" alt="Source Image" style="max-width: 100%; height: auto;" />
</div>
</div>
<!-- Centered buttons -->
<div v-if="imageSrc" style="margin-top: 20px; text-align: center;">
<el-button type="primary" @click="cropImage">裁剪图片</el-button>
<el-button @click="clearImage">重新选择</el-button>
<el-button type="primary" @click="uploadCroppedImage">上传头像</el-button>
</div>
<!-- Conditional display for upload component -->
<el-upload
v-if="!imageSrc"
class="upload-demo"
drag
action="http://localhost:8888/v1/file/singleUploadFile"
multiple
v-model:file-list="fileList"
limit="1"
:show-file-list="false"
:before-upload="beforeUpload"
>
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">
Drop file here or <em>click to upload</em>
</div>
<template #tip>
<div class="el-upload__tip">
jpg/png files with a size less than 500kb
</div>
</template>
</el-upload>
</el-dialog>
</div>
<div>
<img :src="BASE_URL+attraction_detail.imageUrl" alt="">
</div>
</template>
js部分
<script setup>
import { ref, nextTick, onBeforeUnmount } from 'vue';
import { ElMessage } from 'element-plus';
import Cropper from 'cropperjs';
import 'cropperjs/dist/cropper.css';
import axios from 'axios';
const imageSrc = ref(null);
const croppedImageSrc = ref(null);
const dialogTitle = ref({ imgTitle: '上传图片' });
const dialogVisible = ref({ imgCropperVisible: true });
const fileList = ref([]);
const uploadImage = ref(null);
const previewImage = ref(null);
let cropper = null;
const attraction_detail =ref({imageUrl:''})
const beforeUpload = (file) => {
const isImage = file.type.startsWith('image/');
if (!isImage) {
ElMessage.error('只能上传图片文件');
return false;
}
const reader = new FileReader();
reader.onload = async (e) => {
imageSrc.value = e.target.result;
await nextTick();
initCropper();
};
reader.readAsDataURL(file);
return false;
};
const initCropper = () => {
if (cropper) {
cropper.destroy();
}
if (!uploadImage.value) return;
cropper = new Cropper(uploadImage.value, {
aspectRatio: 1,
viewMode: 1,
});
};
const cropImage = () => {
if (cropper) {
const canvas = cropper.getCroppedCanvas({
width: 200,
height: 200,
});
croppedImageSrc.value = canvas.toDataURL('image/png');
}
};
const clearImage = () => {
imageSrc.value = null;
croppedImageSrc.value = null;
fileList.value = [];
if (cropper) {
cropper.destroy();
cropper = null;
}
};
const uploadCroppedImage = async () => {
if (!croppedImageSrc.value) {
ElMessage.error('请先裁剪图片');
return;
}
try {
const blob = dataURLToBlob(croppedImageSrc.value);
const formData = new FormData();
formData.append('file', blob, 'avatar.png'); // 注意这里的表单字段名应为'file'
const response = await axios.post('http://localhost:8888/v1/file/singleUploadFile', formData);
if (response.data) {
ElMessage.success('上传成功');
dialogVisible.value.imgVisible = false;
attraction_detail.value.imageUrl = response.data;
console.log(response.data)
console.log("")
} else {
ElMessage.error(response.data.msg || '上传失败');
}
} catch (error) {
ElMessage.error('上传失败');
}
};
const dataURLToBlob = (dataURL) => {
const arr = dataURL.split(',');
const mime = arr[0].match(/:(.*?);/)[1];
const bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
};
onBeforeUnmount(() => {
if (cropper) {
cropper.destroy();
}
});
</script>
css部分
<style scoped>
.upload-demo .el-upload {
display: block;
width: 100%;
margin-bottom: 20px;
}
.el-upload__text {
color: #606266;
font-size: 14px;
line-height: 22px;
margin-top: 5px;
}
.el-upload__tip {
color: #909399;
font-size: 12px;
line-height: 1.5;
margin-top: 7px;
}
</style>