Vue3后台管理系统(十)文件上传 梦里梦外; 2024-03-26 04:03 22阅读 0赞 **目录** 一、文件上传api 二、封装组件 三、使用案例 -------------------- #### 一、文件上传api #### 在src/api下新建file文件夹,并在file文件夹下新建index.ts和types.ts // src/api/file/types.ts /** * 文件API类型声明 */ export interface FileInfo { name: string; url: string; } // src/api/file/index.ts import request from '@/utils/request'; import { AxiosPromise } from 'axios'; import { FileInfo } from './types'; /** * 上传文件 * * @param file */ export function uploadFileApi(file: File): AxiosPromise<FileInfo> { const formData = new FormData(); formData.append('file', file); return request({ url: '/api/v1/files', method: 'post', data: formData, headers: { 'Content-Type': 'multipart/form-data' } }); } /** * 删除文件 * * @param filePath 文件完整路径 */ export function deleteFileApi(filePath?: string) { return request({ url: '/api/v1/files', method: 'delete', params: { filePath: filePath } }); } #### 二、封装组件 #### **单文件上传组件**、**多文件上传组件** 在src/components下新建Upload文件夹,并在Upload文件夹中新建SingleUpload.vue和MultiUpload.vue <!--src/components/Upload/SingleUpload.vue--> <template> <!-- 上传组件 --> <el-upload class="single-uploader" v-model="imgUrl" :show-file-list="false" list-type="picture-card" :before-upload="handleBeforeUpload" :http-request="uploadFile" > <img v-if="imgUrl" :src="imgUrl" class="single" /> <el-icon v-else class="single-uploader-icon"><Plus /></el-icon> </el-upload> </template> <script setup lang="ts"> import { computed } from 'vue'; import { Plus } from '@element-plus/icons-vue'; import { ElMessage, ElUpload, UploadRawFile, UploadRequestOptions } from 'element-plus'; import { uploadFileApi } from '@/api/file'; const emit = defineEmits(['update:modelValue']); const props = defineProps({ modelValue: { type: String, default: '' } }); const imgUrl = computed<string | undefined>({ get() { return props.modelValue; }, set(val) { // imgUrl改变时触发修改父组件绑定的v-model的值 emit('update:modelValue', val); } }); /** * 自定义图片上传 * * @param options */ async function uploadFile(options: UploadRequestOptions): Promise<any> { const { data: fileInfo } = await uploadFileApi(options.file); imgUrl.value = fileInfo.url; } /** * 限制用户上传文件的格式和大小 */ function handleBeforeUpload(file: UploadRawFile) { if (file.size > 2 * 1048 * 1048) { ElMessage.warning('上传图片不能大于2M'); return false; } return true; } </script> <style scoped> .single-uploader .single { width: 178px; height: 178px; display: block; } </style> <style> .single-uploader .el-upload { border: 1px dashed var(--el-border-color); border-radius: 6px; cursor: pointer; position: relative; overflow: hidden; transition: var(--el-transition-duration-fast); } .single-uploader .el-upload:hover { border-color: var(--el-color-primary); } .el-icon.single-uploader-icon { font-size: 28px; color: #8c939d; width: 178px; height: 178px; text-align: center; } </style> <!--src/components/Upload/MultiUpload.vue--> <!-- 多图上传组件 @author: youlaitech @date 2022/11/20 --> <template> <el-upload v-model:file-list="fileList" list-type="picture-card" :before-upload="handleBeforeUpload" :http-request="handleUpload" :on-remove="handleRemove" :on-preview="handlePreview" :limit="props.limit" > <el-icon><Plus /></el-icon> </el-upload> <el-dialog v-model="dialogVisible"> <img w-full :src="dialogImageUrl" alt="Preview Image" /> </el-dialog> </template> <script setup lang="ts"> import { ref, watch } from 'vue'; import { Plus } from '@element-plus/icons-vue'; import { ElMessage, ElUpload, UploadRawFile, UploadRequestOptions, UploadUserFile, UploadFile, UploadProps } from 'element-plus'; import { uploadFileApi, deleteFileApi } from '@/api/file'; const emit = defineEmits(['update:modelValue']); const props = defineProps({ /** * 文件路径集合 */ modelValue: { type: Array<string>, default: [] as Array<string> }, /** * 文件上传数量限制 */ limit: { type: Number, default: 5 } }); const dialogImageUrl = ref(''); const dialogVisible = ref(false); const fileList = ref([] as UploadUserFile[]); watch( () => props.modelValue, (newVal: string[]) => { const filePaths = fileList.value.map(file => file.url); // 监听modelValue文件集合值未变化时,跳过赋值 if ( filePaths.length > 0 && filePaths.length === newVal.length && filePaths.every(x => newVal.some(y => y === x)) && newVal.every(y => filePaths.some(x => x === y)) ) { return; } fileList.value = newVal.map(filePath => { return { url: filePath } as UploadUserFile; }); }, { immediate: true } ); /** * 自定义图片上传 * * @param params */ async function handleUpload(options: UploadRequestOptions): Promise<any> { // 上传API调用 const { data: fileInfo } = await uploadFileApi(options.file); // 上传成功需手动替换文件路径为远程URL,否则图片地址为预览地址 blob:http:// const fileIndex = fileList.value.findIndex( file => file.uid == (options.file as any).uid ); fileList.value.splice(fileIndex, 1, { name: fileInfo.name, url: fileInfo.url } as UploadUserFile); emit( 'update:modelValue', fileList.value.map(file => file.url) ); } /** * 删除图片 */ function handleRemove(removeFile: UploadFile) { const filePath = removeFile.url; if (filePath) { deleteFileApi(filePath).then(() => { // 删除成功回调 emit( 'update:modelValue', fileList.value.map(file => file.url) ); }); } } /** * 限制用户上传文件的格式和大小 */ function handleBeforeUpload(file: UploadRawFile) { if (file.size > 2 * 1048 * 1048) { ElMessage.warning('上传图片不能大于2M'); return false; } return true; } /** * 图片预览 */ const handlePreview: UploadProps['onPreview'] = uploadFile => { dialogImageUrl.value = uploadFile.url!; dialogVisible.value = true; }; </script> #### 三、使用案例 #### 在src/views/component下新建uploader.vue <!--src/views/component/uploader.vue--> <script setup lang="ts"> import SingleUpload from '@/components/Upload/SingleUpload.vue'; import MultiUpload from '@/components/Upload/MultiUpload.vue'; import { ElForm } from 'element-plus'; import { reactive, ref, toRefs } from 'vue'; const dataFormRef = ref(ElForm); const state = reactive({ formData: { picUrl: 'https://oss.youlai.tech/default/2022/11/20/18e206dae97b40329661537d1e433639.jpg', picUrls: [ 'https://oss.youlai.tech/default/2022/11/20/8af5567816094545b53e76b38ae9c974.webp', 'https://oss.youlai.tech/default/2022/11/20/13dbfd7feaf848c2acec2b21675eb9d3.webp' ] } }); const { formData } = toRefs(state); </script> <template> <div class="app-container"> <el-form ref="dataFormRef" :model="formData"> <el-form-item label="单图上传"> <single-upload v-model="formData.picUrl"></single-upload> </el-form-item> <el-form-item label="多图上传"> <multi-upload v-model="formData.picUrls"></multi-upload> </el-form-item> </el-form> </div> </template> ![add9843d40cb470cb6305cc55e891351.png][] [add9843d40cb470cb6305cc55e891351.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/26/c5c94717420d47e1ab68965c9bc3946f.png
还没有评论,来说两句吧...