feat: 封装多图上传组件

Former-commit-id: d36f4fb6fb9e2c3da42518f6689a78ab2370af57
This commit is contained in:
haoxr
2022-11-21 00:03:16 +08:00
parent 6f001a7713
commit fe6669d813
6 changed files with 246 additions and 92 deletions

View File

@@ -0,0 +1,154 @@
<!--
多图上传组件
@author: haoxr
@date 2022/11/20
@link https://element-plus.gitee.io/zh-CN/component/upload.html
-->
<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[]) => {
console.log('newVal', newVal);
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> {
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) {
console.log('removeFile', removeFile);
const fileUrl = removeFile.url;
if (fileUrl) {
let fileName = removeFile.name;
if (!fileName) {
// 文件名不存在从URL得到文件名
// 例: https://oss.youlai.tech/default/2022/11/20/{uuid}.jpg 得到文件名 2022/11/20/{uuid}.jpg
fileName = fileUrl.substring(fileUrl.indexOf('/', -3) + 1);
}
deleteFileApi(fileName).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>