前言
本文将介绍如何使用 Vue 3 和 Element Plus 创建一个支持图片粘贴上传的组件,并提供详细的代码实现和说明。
组件功能概述
我们的目标是创建一个图片上传组件,具备以下功能:
- 支持用户通过拖拽或点击按钮选择图片上传。
- 支持用户直接粘贴图片到组件中进行上传。
- 显示上传图片的预览,并允许用户删除已上传的图片。
- 提供对上传文件的类型和大小检查。
代码实现
以下是实现上述功能的 Vue 3 组件代码:
<template>
<div @paste="handlePaste">
<el-upload
v-model:file-list="fileList"
action=""
list-type="picture-card"
:on-preview="handlePictureCardPreview"
:before-remove="handleBeforeRemove"
:before-upload="handleBeforeUpload"
:http-request="handleUpload"
>
<el-icon><Plus /></el-icon>
</el-upload>
<el-dialog v-model:visible="dialogVisible">
<img w-full :src="dialogImageUrl" alt="Preview Image" />
</el-dialog>
<span>
Please note that the size of each image should not exceed 3MB, and we support files in JPG and PNG formats.
</span>
</div>
</template>
<script setup lang="ts">
import { Plus } from '@element-plus/icons-vue';
import type { UploadRawFile, UploadRequestOptions } from 'element-plus';
import { ElLoading } from 'element-plus';
import adminApi from '@/api/adminApi';
import showMessage from '~/utils/showMessage';
const fileList = ref<UploadRawFile[]>([]);
const fullPathList = ref<string[]>([]); // Full paths
const pathList = ref<string[]>([]); // Paths without domain
const dialogImageUrl = ref('');
const dialogVisible = ref(false);
const handleUpload = async (options: UploadRequestOptions): Promise<void> => {
const { file } = options;
const formData = new FormData();
formData.append('file', file);
const uploadLoading = ElLoading.service({
lock: true,
text: 'uploading...',
background: 'rgba(0, 0, 0, 0.18)',
});
try {
const { data } = await adminApi.uploadFile(formData);
if (data) {
fullPathList.value.push(data.url);
pathList.value.push(data.path);
emit('update:file-list', pathList.value);
emit('update:full-path-list', fullPathList.value);
}
} catch (error) {
showMessage({ message: 'Upload failed', type: 'error' });
} finally {
uploadLoading.close();
}
};
const handleBeforeUpload = (file: File): boolean => {
const isLt3M = file.size / 1024 / 1024 < 3;
const isAcceptableType = ['image/jpeg', 'image/png'].includes(file.type);
if (!isLt3M) {
showMessage({ message: 'The size of each image should not exceed 3MB', type: 'error' });
return false;
}
if (!isAcceptableType) {
showMessage({ message: 'Only PNG and JPG formats are supported', type: 'error' });
return false;
}
return true;
};
const handleBeforeRemove = (file: UploadRawFile): boolean => {
const index = fileList.value.findIndex((item) => item.uid === file.uid);
if (index !== -1) {
fileList.value.splice(index, 1);
pathList.value.splice(index, 1);
fullPathList.value.splice(index, 1);
emit('update:file-list', pathList.value);
emit('update:full-path-list', fullPathList.value);
}
return true;
};
const handlePictureCardPreview = (file: UploadRawFile): void => {
dialogImageUrl.value = file.url!;
dialogVisible.value = true;
};
const handlePaste = (event: ClipboardEvent) => {
const items = event.clipboardData?.items;
if (!items) return;
for (let i = 0; i < items.length; i++) {
const item = items[i];
if (item.kind === 'file' && item.type.startsWith('image/')) {
const file = item.getAsFile();
if (file) {
const uploadFile: UploadRawFile = {
...file,
uid: Date.now(), // 使用当前时间戳生成唯一的 uid
status: 'success',
url: URL.createObjectURL(file),
};
fileList.value.push(uploadFile);
const formData = new FormData();
formData.append('file', file);
const uploadOptions: UploadRequestOptions = {
file,
onProgress: () => {},
onSuccess: () => {},
onError: () => {},
};
handleUpload(uploadOptions);
}
}
}
};
const emit = defineEmits(['update:file-list', 'update:full-path-list']);
const clearFiles = () => {
fileList.value = [];
pathList.value = [];
fullPathList.value = [];
emit('update:file-list', []);
emit('update:full-path-list', []);
};
defineExpose({ clearFiles });
</script>
<style scoped>
span {
line-height: 20px;
margin-top: 12px;
}
</style>
代码说明
-
组件结构:
el-upload
组件用于处理图片的上传,支持图片预览和删除。el-dialog
组件用于展示图片的详细预览。
-
handleUpload
方法:- 处理上传文件的逻辑,使用
FormData
将文件提交到服务器,并处理加载状态。
- 处理上传文件的逻辑,使用
-
handleBeforeUpload
方法:- 在上传之前检查文件的大小和类型,确保符合要求。
-
handleBeforeRemove
方法:- 处理文件删除时的逻辑,更新文件列表。
-
handlePictureCardPreview
方法:- 显示图片的详细预览。
-
handlePaste
方法:- 处理粘贴事件,从剪贴板中提取图片文件并触发上传。
-
样式:
- 简单的样式调整,使组件界面更加美观。
使用
<template>
<el-form
ref="handleFormRef"
:model="handleForm"
:rules="validateRules"
label-width="100px"
label-position="right"
>
<!-- 表单内容 -->
<el-form-item prop="ImgPathList" label="" required>
<FileUpload v-model:file-list="handleForm.ImgPathList" v-model:full-path-list="handleForm.imgFullPathList" ref="fileUploadRef" />
</el-form-item>
</el-form>
</template>
<script setup lang="ts">
import FileUpload from '@/components/FileUpload/index.vue';
</script>
总结
通过以上代码,我们实现了一个功能完整的图片上传组件,支持用户通过点击、拖拽和粘贴方式上传图片。该组件能够处理图片的上传、预览、删除及类型和大小检查,为用户提供了更好的体验。希望这个示例能帮助你在项目中实现类似功能。
如果你有任何问题或需要进一步的帮助,欢迎在评论区留言!