二次封装el-upload实现图片文件上传(实现一次请求多个上传)

实现图片上传功能

下面是基于element-plus官方提供的一个上传图片的组件:

xml 复制代码
<template>
  <el-upload list-type="picture-card" :auto-upload="false" multiple :on-change="handleChange">
    <el-icon><Plus /></el-icon>

    <template #file="{ file }">
      <div>
        <img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
        <span class="el-upload-list__item-actions">
          <span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
            <el-icon><zoom-in /></el-icon>
          </span>
          <span v-if="!disabled" class="el-upload-list__item-delete" @click="handleDownload(file)">
            <el-icon><Download /></el-icon>
          </span>
          <span v-if="!disabled" class="el-upload-list__item-delete" @click="handleRemove(file)">
            <el-icon><Delete /></el-icon>
          </span>
        </span>
      </div>
    </template>
  </el-upload>
  <el-button @click="handleSuccess">点击上传</el-button>

  <el-dialog v-model="dialogVisible">
    <img w-full :src="dialogImageUrl" alt="Preview Image" />
  </el-dialog>
</template>
<script setup>
import { ref } from 'vue';
import { userUplodImg } from '@/api/user'; // 上传文件的接口地址(如果没有可以发起原生的axios)

const dialogImageUrl = ref('');
const dialogVisible = ref(false);
const disabled = ref(false);
const fileList = ref([]); // 存放图片列表

// 删除操作逻辑
const handleRemove = (file) => {
  console.log(file);
};

const handlePictureCardPreview = (file) => {
  dialogImageUrl.value = file.url;
  dialogVisible.value = true;
};

const handleDownload = (file) => {
  console.log(file);
};
// 文件修改
const handleChange = (file, newFileList) => {
  fileList.value = [...newFileList];
};
// 自定义上传行为
const handleSuccess = async () => {
  const formData = new FormData();
  fileList.value.forEach((file) => {
    formData.append('files[]', file.raw); // 添加文件到FormData
  });
  const res = await userUplodImg(formData);
  fileList.value = [];
  console.log(fileList.value);
  console.log('上传放回的结果:', res);
};

// 如果您没有写接口,可以使用下面的方式发起原生的axios请求

自定义上传行为;
const uploadFiles = async (uploadData) => {
  const formData = new FormData();
  fileList.value.forEach((file) => {
    formData.append('files', file.raw); // 添加文件到FormData
  });

  try {
    const response = await axios.post('接口地址', formData, {
      headers: {
        'Content-Type': 'multipart/form-data',
      },
    });
    // 调用成功回调函数
    uploadData.onSuccess(response.data);
    fileList.value = [];
  } catch (error) {
    // 调用失败回调函数
    uploadData.onError(error);
  }
};
</script>

想要实现我们需要了解下面提供的一些属性:

  1. action:请求的url(因为我们是自定义长传请求,所以不需要设置)
  2. multiple:是否支持多选文件 默认值是false
  3. show-file-list:是否显示已上传文件列表
  4. on-success:文件上传时候的钩子

注意使用这个函数有一个陷阱,那就是我们在选择多选文件的时候这这个钩子会触发多次。这样就没办法实现我们多个文件调用一次接口。所以我们这篇王文章就不使用这个钩子函数

  1. on-change:文件状态改变时候的钩子,添加文件、上传成功和上传失败时都会被调用

这个函数有两个参数,一个是file另一个是fileList

fileList这是一个上传文件列表,类型为数组。每个文件都是一个对象,包含文件的属性,如文件名、大小、类型等。在用户选择文件并上传时,会将文件添加到 fileList 数组中。在回调函数中,可以通过 fileList 数组来获取当前上传文件列表的信息。例如,通过 fileList0.name 可以获取第一个文件的文件名,通过 fileList1.size 可以获取第二个文件的文件大小。

file 它代表当前操作的文件,类型为对象。每当用户上传文件或删除文件时,file 参数都会更新为当前操作文件的信息。在回调函数中,可以通过 file 对象来获取当前操作文件的信息。例如,在上传文件时,可以通过 file.name 获取正在上传的文件的文件名,在删除文件时,可以通过 file.response 获取服务器响应的信息。

6.list-type:文件列表的类型取值为'text' | 'picture' | 'picture-card'(我们需要将取值设置为picture-card)

  1. http-request:覆盖默认的 Xhr 行为,允许自行实现上传文件的请求(因为我们要实现的是多个文件一次提交。所以这个也用不上,如果一次提交一个文件,可以使用)

下面是对这个代码的解释:

  1. 当触发handleChange函数的时候我们需要将第二个代表文件列表的数据存放起来,为了一次发多个文件请求做准备
  2. 点击文件上传的时候需要我们遍历存放的文件列表,创建一个FormData数据类型,将待上传的文件列表(flie.raw)追加到新建的formdata数据类型中,在点击发送即可
  3. 在 Element UI 的上传组件 el-upload 中,fileList.raw 是一个属性,它是一个数组,包含所有已经上传的文件对象,即原始文件对象,不包含任何处理或转换。每个文件对象都包含文件的原始属性,如文件名、大小、类型等。通常情况下,fileList 中的文件对象会在上传之前经过一些处理,例如压缩、裁剪、格式转换等,这些处理会生成新的文件对象,并存放在 fileList 中。而 fileList.raw 则是保存了未经过处理的原始文件对象的数组。 使用 fileList.raw 可以方便地访问原始文件对象的属性,进行一些特殊的处理或获取更具体的信息
  4. 如果你没有设置接口函数,也可以直接发起原生的axios请求
js 复制代码
//自定义上传行为;
const uploadFiles = async (uploadData) => {
  const formData = new FormData();
  fileList.value.forEach((file) => {
    formData.append('files', file.raw); // 添加文件到FormData
  });

  try {
    const response = await axios.post('接口地址', formData, {
      headers: {
        'Content-Type': 'multipart/form-data',
      },
    });
    // 调用成功回调函数
    uploadData.onSuccess(response.data);
    fileList.value = [];
  } catch (error) {
    // 调用失败回调函数
    uploadData.onError(error);
  }
};

注意这里面的一些坑

  1. 因为我们需要实现的是多个文件一次上传请求一次接口,所以就得自己实现请求接口的操作,而一次上传一个文件就不需要。
  2. 网上有的博主在on-change函数中使用了变量进行控制,这样确实可以使on-change只触发一次,但是每次上传的文件就没办法多选。
  3. 当使用el-upload组件上传多个文件时,每个文件会触发一次上传请求。所以就不能让组件自动的发送请求,就需要我们进行控制
  4. 还有一种博主在说可以判断上传文件的数组长度,根据长度达到条件在进行相应的发送请求逻辑,这用方法确实可以实现,但是当我们再次上传的时候,上传接口就失效了。
相关推荐
头茬韭菜几秒前
第 3 篇:「Pydantic 即 Schema」—— 工具生态三层解剖
前端·chrome·ai·openmanus
恋猫de小郭21 分钟前
Flutter 状态管理基准测评,一个很有趣的观点
android·前端·flutter
雪芽蓝域zzs27 分钟前
前端编辑组件wangEditor
前端
风骏时光牛马1 小时前
稳定性治理及疑难问题深度剖析与实战复盘
前端
JeffongTan9 小时前
在LWC中镶嵌VF Page获取用户IP
前端·javascript·salesforce
陆枫Larry11 小时前
Astro 是什么
前端
是立不是利13 小时前
写给设计师的 CSS 博客美学指南
前端·css
默_笙14 小时前
🏝 Docker 就是"房地产开发":从施工图纸到小区物业的容器化指南
前端·javascript
计算机魔术师14 小时前
Rohan Paul 谈用时间跨度衡量智能体能力,并引用 OpenAI 自动化研究实习生里程碑
前端