el-upload上传文件自定义
业务针对性高
主要是应用在表单上传,通过文件上传返回地址,需要与表单参数一并提交
默认上传
通用组件,直接调用,案例:需后端提供接口minio上传,返回url地址
补充上传后文件点击跳转查阅
补充上传地址的header参数
<!-- 针对VITE_UPLOAD_URL地址上传 通用 -->
<template><el-uploadref="uploadRef":action="uploadUrl"v-model:file-list="fileList":auto-upload="true":disabled="formLoading":headers="uploadHeaders":limit="props.limit":on-change="handleChange":on-error="submitFormError":on-exceed="handleExceed":on-success="submitFormSuccess":accept="props.accept"><template #trigger><el-button type="primary">{{ props.name }}</el-button></template><template #tip><div class="el-upload__tip text-red">{{ props.tips }}</div></template><template #file="{ file, index }"><div class="flex items-center gap-4"><el-link :href="file.response?.data" target="_blank" :underline="false" class="text-12px">{{ file.name }}</el-link><Iconclass="mt-2px cursor-pointer"color="var(--el-color-danger)"@click="deleteFile(index)"icon="ep:close"/></div></template></el-upload>
</template>
<script lang="ts" setup>
import { getAccessToken, getTenantId } from '@/utils/auth'
const props = defineProps({name: {type: String,default: () => {return '上传文件'}},size: {require: false,type: Number,default: () => {return 5}},limit: {require: false,type: Number,default: () => {return 1}},tips: {require: false,type: String,default: () => {return '支持图片格式(JPG、PNG)和PDF文件,最大5MB'}},accept: {require: false,type: String,default: () => {return '.jpeg, .jpg, .png, .pdf'}}
})
const uploadUrl = import.meta.env.VITE_UPLOAD_URL
const message = useMessage() // 消息弹窗
const emit = defineEmits(['success', 'delete'])
const uploadHeaders = ref({Authorization: 'Bearer ' + getAccessToken(),'tenant-id': getTenantId()
})
const formLoading = ref(false) // 表单的加载中
const fileList = ref([] as any) // 文件列表
const uploadRef = ref()/** 处理上传的文件发生变化 */
const handleChange = (file) => {const fileName = file.nameconst fileType = fileName.substring(fileName.lastIndexOf('.'))if (props.accept.indexOf(fileType) === -1) {message.warning('上传的文件不符合所需的格式!')fileList.value.splice(-1)return}const maxSize = props.sizeconst size = maxSize * 1024 * 1024if (file.size > size) {unref(uploadRef)?.clearFiles()message.warning('上传文件大小不超过' + props.size + 'MB')return}
}
/** 文件数超出提示 */
const handleExceed = (): void => {message.error('最多只能上传' + props.limit + '份文件!')
}
/** 上传错误提示 */
const submitFormError = (): void => {unref(uploadRef)?.clearFiles()message.error('文件上传失败,请您重新上传!')
}
/** 文件上传成功处理 */
const submitFormSuccess = (res) => {emit('success', res.data)
}
const deleteFile = (index) => {emit('delete', fileList.value.length)fileList.value.splice(index, 1)
}
</script>
<style lang="scss" scoped>
:deep(.el-upload-list__item-info) {max-width: 350px;
}
</style>
案例使用
<el-form-item label="证书文件" prop="url"><uploadref="uploadRef"@success="getFileUrl"@delete="deleteFile"/></el-form-item>
const getFileUrl = (url: string) => {// TODO
}
const deleteFile = async (index: number) => {// TODO
}
取消默认上传
自定义上传地址
案例:点击按钮等才调用上传功能,利用FormData表单提交文件
<template><el-uploadref="uploadRef"v-model:file-list="fileList"action="#":auto-upload="false":disabled="formLoading":limit="1":on-change="handleChange":on-remove="hanldeRemove":on-exceed="handleExceed"accept=".jpg, .png, .jpeg, .pdf, .doc, .docx"><template #trigger><el-button type="primary">上传文件</el-button></template><template #tip><div class="el-upload__tip text-red">请上传大小不超过{{ props.size }}MB的图片/PDF/Word文件</div></template></el-upload>
</template>
<script lang="ts" setup>
const props = defineProps({size: {require: false,type: Number,default: 200}
})
const message = useMessage() // 消息弹窗
// 暴露出success接口上传成功返回,setUpload:上传文件操作返回true,删除返回false
const emit = defineEmits(['success', 'setUpload'])
const formLoading = ref(false) // 表单的加载中
const fileList = ref([]) // 文件列表
const uploadRef = ref()
const fileTypes = '.jpeg, .jpg, .png, .pdf, .doc, .docx'
/** 处理上传的文件发生变化 */
const handleChange = (file) => {const fileName = file.nameconst fileType = fileName.substring(fileName.lastIndexOf('.'))if (fileTypes.indexOf(fileType) === -1) {message.warning('上传的文件不符合所需的格式!')fileList.value.splice(-1)return}const maxSize = props.sizeconst size = maxSize * 1024 * 1024if (file.size > size) {unref(uploadRef)?.clearFiles()message.warning('上传文件大小不超过' + props.size + 'MB')return}if (file.status === 'ready') {emit('setUpload', true)}
}
const hanldeRemove = () => {emit('setUpload', false)
}
/** 文件数超出提示 */
const handleExceed = (): void => {message.error('最多只能上传1份文件!')
}
// 外部调用才一并上传文件接口请求
const submitFun = () => {if (!fileList.value.length) returnreturn new Promise(async (resolve) => {let formData = new FormData()fileList.value.map((item: any) => {formData.append('file', item.raw)})// 可直接 resolve(formData),外部调用接口let res = await xxxformLoading.value = falseif (res.data) resolve(res.data)else message.warning('文件上传失败')})
}
defineExpose({ submitFun })
</script>
<style lang="scss" scoped>
:deep(.el-upload-list__item-info) {max-width: 350px;
}
</style>
取消自动上传
针对多个文件上传,利用submitFormSuccess返回多个后,拼接成字符串返回
setUpload 是针对外部调用时监听到上传文件操作(未调用接口的),取消表单校验验操作
针对校验问题写了很多,后续再优化
<template><el-uploadref="uploadRef"v-model:file-list="showList":action="url":auto-upload="false":disabled="formLoading":headers="uploadHeaders":limit="props.limit":on-change="handleChange":on-remove="hanldeRemove":on-error="submitFormError":on-exceed="handleExceed":on-success="submitFormSuccess"accept=".jpg, .png, .jpeg"><template #trigger><el-button type="primary">上传图片</el-button></template><template #tip><div class="el-upload__tip text-red">请上传大小不超过{{ props.size }}MB的图片,最多上传{{ props.limit }}张</div></template></el-upload>
</template>
<script lang="ts" setup>
import { getAccessToken, getTenantId } from '@/utils/auth'
const props = defineProps({size: {require: false,type: Number,default: 20},limit: {require: false,type: Number,default: 1}
})
const url = import.meta.env.VITE_UPLOAD_URL
const message = useMessage() // 消息弹窗
const emit = defineEmits(['success', 'setUpload'])
const uploadHeaders = ref() // 上传 Header 头
const formLoading = ref(false) // 表单的加载中
const fileList = ref([]) // 文件列表
const showList = ref([]) // 文件列表
const uploadRef = ref()
const imgTypes = ['image/jpeg', 'image/png', 'image/jpg']
/** 处理上传的文件发生变化 */
const handleChange = (file, files) => {if (imgTypes.indexOf(file.raw.type) === -1) {message.warning('上传的文件不符合所需的格式!')showList.value.splice(-1)return}const maxSize = props.sizeconst size = maxSize * 1024 * 1024if (file.size > size) {unref(uploadRef)?.clearFiles()message.warning('上传文件大小不超过' + props.size + 'MB')return}if (file.status === 'ready') {fileList.value = filesemit('setUpload', true)}
}
// @ts-ignore文件移除
const hanldeRemove = (file, files) => {fileList.value = filesif (files.length) emit('setUpload', false)
}
/** 文件数超出提示 */
const handleExceed = (): void => {message.error('最多只能上传' + props.limit + '份文件!')
}
/** 上传错误提示 */
const submitFormError = (): void => {unref(uploadRef)?.clearFiles()message.error('文件上传失败,请您重新上传!')
}
/** 文件上传成功处理 */
const fileNum = ref(0)
// @ts-ignore
const submitFormSuccess = (val, file, files) => {fileNum.value++if (fileNum.value === files.length) {let ids = [] as anyfiles.map((item: any) => {ids.push(item.response.data)})formLoading.value = falsefileNum.value = 0fileList.value = []emit('success', ids.join(','))}
}
// 说明 在文件上传处理fileList.value为[],故再次调用时不会执行改方法
// 外部调用
const submitFun = () => {if (!fileList.value.length) returnreturn new Promise(() => {// 提交请求uploadHeaders.value = {Authorization: 'Bearer ' + getAccessToken(),'tenant-id': getTenantId()}unref(uploadRef)?.submit()})
}
defineExpose({ submitFun })
</script>
<style lang="scss" scoped>
:deep(.el-upload-list__item-info) {max-width: 300px;
}
</style>
调用案例
<el-form-item label="相关文件" prop="url"><upload ref="uploadRef" @success="getFileUrl" @set-upload="setUpload" />
</el-form-item>
// 上传图片
const getFileUrl = (url) => {formData.value.url= urlsubmitForm()
}
// 表单校验
const setUpload = (bol) => {if (bol) {formData.value.url= ''unref(formRef).clearValidate('url')} else {unref(formRef).validateField('url')}
}
// 表单提交按钮
const submitForm = async () => {await uploadRef.value.submitFun()await formRef.value.validate()//表单校验成功,和表单参数一起提交
}