二次封装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 数组来获取当前上传文件列表的信息。例如,通过 fileList[0].name 可以获取第一个文件的文件名,通过 fileList[1].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. 还有一种博主在说可以判断上传文件的数组长度,根据长度达到条件在进行相应的发送请求逻辑,这用方法确实可以实现,但是当我们再次上传的时候,上传接口就失效了。
相关推荐
Leyla13 分钟前
【代码重构】好的重构与坏的重构
前端
影子落人间17 分钟前
已解决npm ERR! request to https://registry.npm.taobao.org/@vant%2farea-data failed
前端·npm·node.js
世俗ˊ41 分钟前
CSS入门笔记
前端·css·笔记
子非鱼92141 分钟前
【前端】ES6:Set与Map
前端·javascript·es6
6230_1 小时前
git使用“保姆级”教程1——简介及配置项设置
前端·git·学习·html·web3·学习方法·改行学it
想退休的搬砖人1 小时前
vue选项式写法项目案例(购物车)
前端·javascript·vue.js
加勒比海涛1 小时前
HTML 揭秘:HTML 编码快速入门
前端·html
啥子花道1 小时前
Vue3.4 中 v-model 双向数据绑定新玩法详解
前端·javascript·vue.js
麒麟而非淇淋1 小时前
AJAX 入门 day3
前端·javascript·ajax
茶茶只知道学习2 小时前
通过鼠标移动来调整两个盒子的宽度(响应式)
前端·javascript·css