Vue3+Ant Design Vue 实现手动异步文件上传(含大小校验、弹窗上传)

需求:选择需要上传的文件后阻止默认上传,在点击弹窗的确认按钮后触发上传文件事件。

模板部分(上传弹窗+上传组件)

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

相关推荐
犀利的毛豆豆5 小时前
useCallback
前端
犀利的毛豆豆5 小时前
React.memo和useCallback组合使用
前端
mONESY5 小时前
浏览器里跑 DeepSeek-R1,这份 worker.js 到底写了什么
javascript
用户6919026813395 小时前
用浏览器 WebGPU跑DPSK大模型(1) - 模型的下载和前端下载进度的显示
javascript·react.js·架构
夏幻灵5 小时前
Vue 2 与 Vue 3 在应用初始化上的设计差异与技术演进
前端·javascript·vue.js
捌年5 小时前
5分钟搞定工作周报!TRAE Work自动梳理零散工作记录实战
前端
悟空瞎说6 小时前
Three.js 架构实践:用 MVC 模式组织你的 3D 应用
前端·javascript
光影少年6 小时前
react navite本地存储:AsyncStorage、MMKV、文件存储
前端·react native·react.js
曹牧6 小时前
C#:问号
前端·数据库·c#
王林不想说话6 小时前
JavaScript 从入门到进阶:一篇覆盖核心知识、运行机制与工程实践
javascript