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

相关推荐
wordbaby1 小时前
Web端热敏标签打印完整解决方案(QZ Tray + 译维A42)
前端
swipe1 小时前
03|Axios 请求进了后端之后:Controller、Request、Response 是怎么接住它的?
前端·后端·全栈
meilindehuzi_a1 小时前
Vue3进阶基础:指令修饰符、v-model表单绑定、动态样式、计算属性与侦听器实战
前端·javascript·vue.js
csdn2015_1 小时前
vue 前端运行命令
前端·javascript·vue.js
swipe1 小时前
02|从 `pnpm dev` 到 Spring Boot 启动:后端服务到底怎么跑起来?
前端·后端·全栈
swipe1 小时前
01|前端人第一次打开 Spring Boot 项目,应该先看哪里?
前端·后端·全栈
Cobyte2 小时前
根据浏览器解析 HTML 的规范实现 HTML 解析器
前端·javascript·vue.js
阿懂在掘金2 小时前
做命令式弹窗工具应该考虑什么——我为什么把 vue-layerx 设计成这样
前端·前端框架·函数式编程
太平洋月光2 小时前
AI 快捷指令:Cursor Rules · Commands · Skills
前端·ai编程