Ant Design Vue Upload组件自定义上传与表单集成方案

作者:南栀

时间:2026-10-25

浏览:189

本文详解Ant Design Vue中Upload组件在表单环境下的自定义上传实现。针对组件change事件频繁触发导致的校验异常,通过getValueFromEvent结合自定义handleChange方法精准控制文件列表状态。文章提供了多文件上传组件的内联处理、customRequest逻辑定义及完整代码示例,解决上传状态与表单提交不同步的问题。

文章目录

Ant Design Vue Upload组件自定义上传结合表单提交

在表单中内联多个文件上传组件

在使用Ant Design Vue的Upload组件时,会遇到一个现象:文件状态每次变更都会触发change事件。这意味着无论是上传成功、失败还是删除文件,该事件均会被触发。特别需要注意的是,删除文件后也会触发change事件,具体表现可参考下图:

Ant Design Vue Upload组件自定义上传结合表单提交

Ant Design Vue Upload组件自定义上传结合表单提交

即使返回结果为空,只要触发了change事件,该事件默认会返回如下结构的数据对象:

{
  file: { /* ... */ },
  fileList: [ /* ... */ ]
}

正是由于上述机制,每次提交表单时,即使没有附件,系统也会进行校验。因此,我们选择放弃使用Upload组件自带的change事件,转而采用表单配置中的getValueFromEvent方法(由于涉及多个上传组件,此处额外传递了一个key参数以区分)。

<a-upload
  name="file"
  v-decorator="[
    'registerCertificatePath',
    {
      rules: [
        { required: true, message: '请上传公司注册信息证书!' }
      ],
      getValueFromEvent: e =>
        handleChange(e, 'registerCertificatePath')
    }
  ]"
  :file-list="registerCertificatePathList"
  :customRequest="file => uploadFile(file, 'registerCertificate')"
>
  <a-button><a-icon type="upload" />上传</a-button>
</a-upload>

我们需要定义两个核心方法:用于重置表单组件的setFileList方法,以及用于处理组件状态变化的handleChange回调(注意:这里并非直接调用Upload组件的change事件)。

setFileList(fileKey) {
  // 根据filekey值清空指定的上传文件列表
  this[`${fileKey}List`] = [];
  // 清除对应的表单组件值
  this.lastForm.setFieldsValue({ [fileKey]: "" });
},
handleChange({ file, fileList }, key) {
  if (file.status === "removed" || file.status === "error") {
    // 当这两种状态时调用setFileList方法
    this.setFileList(key);
    return "";
  }
  // 给对应的上传组件文件列表赋值
  this[`${key}List`] = fileList;
  // 赋值给对应表单
  return file;
}

以下是具体的上传实现代码:

uploadRequest(param)
 .then(({ success, message, data }) => {
   if (success) {
     const { fileName, filePath } = data;
     this.fileData[`${fileKey}Path`] = filePath;
     this.fileData[`${fileKey}Name`] = fileName;
     this.$message.success(message);
     // 上传成功将状态设置为 done
     file.onSuccess();
   } else {
     this.$message.warning(message);
     // 上传成功将状态设置为 error
     file.onError();
   }
 })
 .catch(error => {
   this.$message.error("上传失败!");
   console.log("上传失败:", error);
   // 上传成功将状态设置为 error
   file.onError();
 });

完整代码示例如下:

<template>
  <div class="last">
    <a-form
      :form="lastForm"
      :label-col="{ span: 10 }"
      :wrapper-col="{ span: 14 }"
      @submit="lastSubmit"
    >
      <a-row>
        <a-col :span="8">
          <a-form-item label="公司注册信息证书">
            <a-upload
              name="file"
              v-decorator="[
                'registerCertificatePath',
                {
                  rules: [
                    { required: true, message: '请上传公司注册信息证书!' }
                  ],
                  getValueFromEvent: e =>
                    handleChange(e, 'registerCertificatePath')
                }
              ]"
              :file-list="registerCertificatePathList"
              :customRequest="file => uploadFile(file, 'registerCertificate')"
            >
              <a-button><a-icon type="upload" />上传</a-button>
            </a-upload>
          </a-form-item>
        </a-col>
        <a-col :span="8">
          <a-form-item label="营业执照附件">
            <a-upload
              name="file"
              v-decorator="[
                'businessLicPath',
                {
                  rules: [{ required: true, message: '请上传营业执照附件!' }],
                  getValueFromEvent: e => handleChange(e, 'businessLicPath')
                }
              ]"
              :file-list="businessLicPathList"
              :customRequest="file => uploadFile(file, 'businessLic')"
            >
              <a-button><a-icon type="upload" />上传</a-button>
            </a-upload>
          </a-form-item>
        </a-col>
        <a-col :span="8">
          <a-form-item label="身份证件附件">
            <a-upload
              name="file"
              v-decorator="[
                'idCardCertificatePath',
                {
                  rules: [{ required: true, message: '请上传身份证件附件!' }],
                  getValueFromEvent: e =>
                    handleChange(e, 'idCardCertificatePath')
                }
              ]"
              :file-list="idCardCertificatePathList"
              :customRequest="file => uploadFile(file, 'idCardCertificate')"
            >
              <a-button><a-icon type="upload" />上传</a-button>
            </a-upload>
          </a-form-item>
        </a-col>
      </a-row>
      <div class="btn">
        <a-button @click="prev">
          上一步
        </a-button>
        <a-button type="primary" html-type="submit">
          完成注册
        </a-button>
      </div>
    </a-form>
  </div>
</template>
<script>
import { mapState } from "vuex";
import { uploadRequest } from "../../request/http";
export default {
  computed: {
    ...mapState(["oid", "billKey"])
  },
  data() {
    return {
      lastForm: this.$form.createForm(this, { name: "lastForm" }),
      fileData: {
        registerCertificateName: "", // 公司注册证书
        registerCertificatePath: "", // 公司注册证书路径
        businessLicName: "", // 营业执照附件
        businessLicPath: "", // 营业执照附件路径
        idCardCertificateName: "", // 身份证件附件
        idCardCertificatePath: "" // 身份证件附件路径
      },
      registerCertificatePathList: [],
      businessLicPathList: [],
      idCardCertificatePathList: []
    };
  },
  methods: {
    lastSubmit(e) {
      e.preventDefault();
      this.lastForm.validateFields((err, values) => {
        if (!err) {
          values = this.fileData;
          this.$emit("sub", values);
        }
      });
    },
    prev() {
      this.$emit("prev");
    },
    setFileList(fileKey) {
      this[`${fileKey}List`] = [];
      this.lastForm.setFieldsValue({ [fileKey]: "" });
    },
    handleChange({ file, fileList }, key) {
      if (file.status === "removed" || file.status === "error") {
        this.setFileList(key);
        return "";
      }
      this[`${key}List`] = fileList;
      return file;
    },
    uploadFile(file, fileKey) {
      const formData = new FormData();
      formData.append("file", file.file);
      const param = {
        billKey: this.billKey,
        billId: this.oid,
        data: formData
      };
      uploadRequest(param)
        .then(({ success, message, data }) => {
          if (success) {
            const { fileName, filePath } = data;
            this.fileData[`${fileKey}Path`] = filePath;
            this.fileData[`${fileKey}Name`] = fileName;
            this.$message.success(message);
            file.onSuccess();
          } else {
            this.$message.warning(message);
            file.onError();
          }
        })
        .catch(error => {
          this.$message.error("上传失败!");
          console.log("上传失败:", error);
          file.onError();
        });
    }
  }
};
</script>
<style lang="less">
.last {
  .ant-upload {
    width: 100%;
    text-align: left;
    .ant-btn{
      width: 230px;
    }
  }
  .ant-upload-list {
    text-align: left;
  }
}
</style>

Ant Design Vue自定义上传逻辑实现

实际上,使用Ant Design自带的上传逻辑也是可行的,当然也可以采用自定义上传逻辑。由于个人感觉某些功能通过自带逻辑难以实现或实现过程较为繁琐,因此这里重点记录自定义上传逻辑的实现方式。

<a-upload
  :action="$rootUrl+'BillAudit/BillFile/UploadFile'"
  :multiple="true"
  :file-list="fileList"
  name="files"
  :customRequest="customRequest"
  :data="{type:3}"
  @change="handleChange"
>
  <a-button> <a-icon type="upload" /> 上传附件 </a-button>
</a-upload>

customRequest方法的逻辑处理如下:

customRequest(data) {
  const formData = new FormData()
  formData.append('files', data.file)
  formData.append('type', 3)
  // 这里的token根据自身情况修改
  // formData.append('token', 'dfjdgfdgskdfkaslfdskf')
  this.saveFile(formData)
},
saveFile(data) {
  axios({
    method: 'post',
    url: this.$rootUrl+'BillAudit/BillFile/UploadFile',
    data: data
  }).then(res=>{
    let fileList = JSON.parse(JSON.stringify(this.fileList))
    if(res.data.code == 1) {
      fileList.map(file=>{
        file.url = res.data.data
        file.status = 'done'
      })
      this.$message.success('上传成功')
    }else {
      fileList.map(file=>{
        file.status = 'error'
      })
      this.$message.error(res.data.message)
    }
    this.fileList = fileList
  }).catch(err=>{
    let fileList = JSON.parse(JSON.stringify(this.fileList))
    fileList.map(file=>{
        file.status = 'error'
      })
      this.fileList = fileList
    this.$message.error('服务器内部错误')
  })
},

最终效果展示:

Ant Design Vue Upload组件自定义上传结合表单提交

以上为个人经验分享,希望能为大家提供参考,也希望大家多多支持本站。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章