需求:选择需要上传的文件后阻止默认上传,在点击弹窗的确认按钮后触发上传文件事件。
模板部分(上传弹窗+上传组件)
html
<template>
<!-- 上传文件按钮 -->
<a-button type="primary" @click="handleUpload">
<upload-outlined />
上传文件
</a-button>
<!-- 上传文件弹窗 -->
<a-modal
v-model:visible="uploadModalVisible"
title="上传文件"
:confirm-loading="uploading"
@ok="handleUploadOk"
@cancel="handleUploadCancel"
>
<a-upload
v-model:file-list="fileList"
:before-upload="beforeUpload"
:max-count="1"
@remove="handleRemoveFile"
>
<a-button>
<upload-outlined />
选择文件
</a-button>
</a-upload>
</a-modal>
</template>
JS 逻辑(核心异步上传逻辑)
基于 Vue3 setup 语法,封装所有上传核心逻辑,包含状态定义、校验、请求、状态重置:
javascript
import { ref } from 'vue';
import { message } from 'ant-design-vue';
import { UploadOutlined } from '@ant-design/icons-vue';
// 后端文件上传接口
import { FileApi } from '@/api/fileApi';
export default {
name: 'FileUpload',
components: {
UploadOutlined
},
setup() {
// 弹窗显示状态
const uploadModalVisible = ref(false);
// 选中的文件列表
const fileList = ref([]);
// 上传加载状态
const uploading = ref(false);
// 打开上传弹窗
const handleUpload = () => {
uploadModalVisible.value = true;
};
/**
* 上传前文件校验
* @param {File} file - 选中的文件对象
* @returns {boolean} 阻止/允许上传
*/
const beforeUpload = (file) => {
// 限制文件大小10MB
const isLt10M = file.size / 1024 / 1024 < 10;
if (!isLt10M) {
message.error('文件大小不能超过 10MB');
}
// 返回false 阻止组件自动上传,实现手动上传
return false;
};
// 手动移除已选文件
const handleRemoveFile = () => {
fileList.value = [];
};
/**
* 确认上传(核心异步上传方法)
*/
const handleUploadOk = async () => {
// 未选择文件校验
if (fileList.value.length === 0) {
message.warning('请选择要上传的文件');
return;
}
// 开启加载状态
uploading.value = true;
try {
// 组装FormData文件参数
const formData = new FormData();
// 获取原生文件对象,塞入表单
formData.append('file', fileList.value[0].originFileObj);
// 调用后端上传接口,异步请求
const res = await FileApi.uploadFile(formData);
if (res.success) {
message.success('文件上传成功');
// 关闭弹窗、清空文件列表
uploadModalVisible.value = false;
fileList.value = [];
// 可在此处调用刷新列表方法,更新数据
// await fetchData();
} else {
message.error(res.message || '文件上传失败');
}
} catch (error) {
// 捕获接口异常、网络异常
message.error('文件上传失败,网络异常');
console.error('文件上传错误:', error);
} finally {
// 关闭加载状态
uploading.value = false;
}
};
// 取消上传,重置状态
const handleUploadCancel = () => {
uploadModalVisible.value = false;
fileList.value = [];
};
return {
uploadModalVisible,
fileList,
uploading,
handleUpload,
beforeUpload,
handleUploadOk,
handleUploadCancel,
handleRemoveFile
};
}
};
常见踩坑问题总结
问题1:文件选择后自动上传,无法手动控制
解决方案:before-upload 钩子必须返回 false,缺一不可。
问题2:后端接收不到文件
解决方案:必须使用 originFileObj 获取原生文件,不要直接传递 fileList 中的对象。
问题3:上传过程中重复点击提交
解决方案:绑定confirm-loading 状态,上传期间禁用按钮。
问题4:上次上传文件残留,二次上传无需选文件直接提交
解决方案:弹窗关闭、上传成功、移除文件时,手动清空 fileList。