Element-plus el-upload 图片上传二次封装,支持一次上传多张图片

组件

  • 组件名称 CgUploadImg.vue
<template>
  <div class="upload-box">
    <!-- 多图片显示区域 -->
    <div class="image-list" v-if="props.limit > 1">
      <div v-for="(img, index) in imageList" :key="index" class="image-item">
        <img :src="img.includes('http') ? img : baseURL + img" class="upload-image" />
        <div class="upload-handle" @click.stop>
          <div class="handle-icon" @click.stop="editImg(index)" v-if="!self_disabled">
            <el-icon :size="props.iconSize">
              <Edit />
            </el-icon>
            <span v-if="!props.iconSize">{
  
  { $t('common.editBtn') }}</span>
          </div>
          <div class="handle-icon" @click.stop="previewImg(img)">
            <el-icon :size="props.iconSize">
              <ZoomIn />
            </el-icon>
            <span v-if="!props.iconSize">{
  
  { $t('common.viewBtn') }}</span>
          </div>
          <div class="handle-icon" @click.stop="deleteImg(index)" v-if="!self_disabled">
            <el-icon :size="props.iconSize">
              <Delete />
            </el-icon>
            <span v-if="!props.iconSize">{
  
  { $t('common.delBtn') }}</span>
          </div>
        </div>
      </div>

      <!-- 上传按钮 -->
      <el-upload v-if="!isLimitExceeded" action="#" :id="uuid" :class="['upload', 'upload-item', self_disabled ? 'disabled' : '', drag ? 'no-border' : '']" :multiple="false" :disabled="self_disabled" :show-file-list="false"
        :http-request="handleHttpUpload" :before-upload="beforeUpload" :on-success="uploadSuccess" :on-error="uploadError" :drag="drag" :accept="fileType.join(',')">
        <div class="upload-empty">
          <slot name="empty">
            <el-icon>
              <Plus />
            </el-icon>
          </slot>
        </div>
      </el-upload>
    </div>

    <!-- 单图片模式保持原样 -->
    <el-upload v-else action="#" :id="uuid" :class="['upload', self_disabled ? 'disabled' : '', drag ? 'no-border' : '']" :multiple="false" :disabled="self_disabled" :show-file-list="false" :http-request="handleHttpUpload"
      :before-upload="beforeUpload" :on-success="uploadSuccess" :on-error="uploadError" :drag="drag
<think>我们正在解决Vue3 + Element Plusel-upload组件手动上传二进制图片的问题。根据引用内容,关键点在于: 1. 使用el-upload组件的http-request覆盖默认上传行为。 2. 在http-request方法中手动创建FormData对象,并确保将原生File对象(即raw属性)添加到FormData中。 3. 使用axios等库发送FormData,注意设置正确的请求头(通常浏览器会自动设置multipart/form-data的boundary,所以我们只需将Content-Type设为undefined,或者不设置,让浏览器自动设置)。 4. 注意:传递FormData时,必须使用data选项,而不是params(引用[5]指出)。 实现步骤: 1. 在template中,设置el-upload组件的属性::auto-upload="false"(关闭自动上传),:on-change="handleChange"(文件变化时触发),然后添加一个按钮触发上传动作(或者手动触发上传)。 2. 使用el-upload组件的http-request属性覆盖默认上传,或者使用手动上传方式(通常通过ref调用submit方法)。但根据问题,我们需要手动创建FormData,所以我们选择使用http-request自定义上传。 或者,另一种常见做法是:关闭自动上传,收集文件列表,然后手动触发上传函数(在函数中创建FormData并发送请求)。 但是,根据引用[1],el-upload组件返回的文件对象是一个自定义对象,其中包含一个raw属性,该属性才是原生的File对象。因此,在构建FormData时,必须使用file.raw。 我们参考引用[3]和[4]中的API调用方式,以及引用[5]中关于传递data的注意事项。 下面给出一个完整的实现示例: ### 模板部分 ```html <template> <div> <el-upload action="" <!-- 不设置action,因为我们自己处理上传 --> list-type="picture-card" <!-- 照片墙样式 --> :auto-upload="false" <!-- 关闭自动上传 --> :on-change="handleChange" <!-- 文件状态改变时的回调 --> :file-list="fileList" <!-- 绑定的文件列表 --> multiple <!-- 支持多选 --> > <i class="el-icon-plus"></i> </el-upload> <el-button @click="submitUpload">上传图片</el-button> </div> </template> ``` ### 脚本部分 ```javascript <script setup> import { ref } from &#39;vue&#39;; import axios from &#39;axios&#39;; // 或者使用项目封装的axios实例 // 文件列表 const fileList = ref([]); // 文件改变时的处理 const handleChange = (file, fileListRef) => { // 注意:这里我们使用fileListRef来更新文件列表(或者也可以直接使用fileList.value) fileList.value = fileListRef; }; // 提交上传 const submitUpload = () => { // 创建FormData对象 const formData = new FormData(); // 遍历fileList,将每个文件的原生File对象(raw)添加到FormData中 fileList.value.forEach((file) => { // 注意:file.raw是原生File对象 formData.append(&#39;files&#39;, file.raw); // 字段名根据后端接口要求,可能是&#39;file&#39;或&#39;files[]&#39;等 }); // 可以添加其他表单数据 // formData.append(&#39;param1&#39;, &#39;value1&#39;); // 发送请求(使用axios) axios.post(&#39;/your/upload/endpoint&#39;, formData, { headers: { &#39;Content-Type&#39;: &#39;multipart/form-data&#39; // 也可以不设置,浏览器会自动设置,但需要加上boundary。如果设置,注意不要自己写boundary,浏览器会自动处理。 // 或者直接不设置Content-Type,让axios自动添加:默认情况下,当发送FormData时,axios会自动设置Content-Type为&#39;multipart/form-data&#39;并加上boundary // 所以这里可以省略,或者写为:&#39;Content-Type&#39;: undefined } }).then(response => { console.log(&#39;上传成功&#39;, response); }).catch(error => { console.error(&#39;上传失败&#39;, error); }); }; </script> ``` ### 注意事项 1. 后端接口要求:如果后端接口接收的是多个文件,那么字段名可能是`files[]`(对于PHP)或`files`(根据后端框架),请根据实际情况修改`formData.append`的字段名。引用[3]中接口使用`@RequestParam("files") MultipartFile[] files`,所以字段名应为`files`(如果是单个文件则用`file`)。 2. 如果只上传单个文件,也可以使用`formData.append(&#39;file&#39;, fileList.value[0].raw)`。 3. 请求头:在发送FormData时,一般不需要手动设置Content-Type,浏览器会自动设置。但是,如果遇到问题,可以尝试设置`&#39;Content-Type&#39;: undefined`(如引用[4]所示)或`&#39;Content-Type&#39;: &#39;multipart/form-data&#39;`(由浏览器自动添加boundary)。通常,axios在检测到数据是FormData时会自动设置正确的请求头。 4. 引用[5]强调:一定要用`data`传递FormData,而不是`params`。 ### 修改版本(使用http-request) 另一种方式是利用el-upload的http-request属性,这样就不需要手动触发上传按钮,而是每个文件都会触发自定义上传方法。但注意,这种方式对于多个文件会分别发送多个请求。如果需要在一个请求中发送多个文件,则不适合使用http-request,而适合上面的方式(收集所有文件后一起上传)。 如果后端要求每个文件单独上传,则可以使用http-request: ```html <el-upload action="" :http-request="customUpload" ...其他属性 > ... </el-upload> ``` 然后在方法中: ```javascript const customUpload = (options) => { const { file } = options; // options中包含了file对象,注意这个file就是组件内部处理后的对象,我们需要的是file.raw const formData = new FormData(); formData.append(&#39;file&#39;, file.raw); // 字段名根据后端接口 axios.post(&#39;/upload/single&#39;, formData, { // 配置项 }).then(...).catch(...); }; ``` ### 总结 根据需求,我们提供了两种方法: 1. 收集多个文件后统一上传(适合一次提交多文件)。 2. 每个文件单独上传(使用http-request)。 请根据实际情况选择。 §§相关问题§§ 1.Element Plusel-upload组件中,如何实现上传前文件格式和大小的校验? 2. 如何处理el-upload组件上传过程中的进度显示? 3. 如何实现图片上传后的预览和删除功能? </think>在 Vue3 + Element Plus 中使用 `el-upload` 组件手动创建 FormData 上传二进制图片的实现方法如下,关键步骤参考了站内引用内容: ### 实现步骤及代码示例 #### 1. 模板设置 ```html <template> <el-upload action="" <!-- 禁用默认上传 --> list-type="picture-card" <!-- 照片墙样式 --> :auto-upload="false" <!-- 关闭自动上传 --> :on-change="handleFileChange" <!-- 文件变化监听 --> :file-list="fileList" multiple > <el-icon><Plus /></el-icon> </el-upload> <el-button @click="submitUpload">手动上传</el-button> </template> ``` #### 2. 脚本逻辑 ```javascript <script setup> import { ref } from &#39;vue&#39;; import axios from &#39;axios&#39;; // 或项目封装的请求库 const fileList = ref([]); // 文件变化时存储文件 const handleFileChange = (file, files) => { fileList.value = files; }; // 手动上传 const submitUpload = async () => { if (!fileList.value.length) return; const formData = new FormData(); // 关键:必须使用 .raw 获取原生 File 对象 [^1] fileList.value.forEach(file => { formData.append(&#39;files&#39;, file.raw); // 字段名需与后端一致(如 files[]/file) }); // 可选:添加其他参数 formData.append(&#39;param1&#39;, &#39;value1&#39;); try { // 发送请求(必须用 data 而非 params)[^5] const res = await axios.post(&#39;/api/upload&#39;, formData, { headers: { &#39;Content-Type&#39;: &#39;multipart/form-data&#39; // 或 undefined 由浏览器自动设置 [^4] } }); console.log(&#39;上传成功&#39;, res); } catch (error) { console.error(&#39;上传失败&#39;, error); } }; </script> ``` ### 核心注意事项 1. **文件对象处理** 必须使用 `file.raw` 获取原生 File 对象(二进制数据),直接使用组件对象会导致上传失败 [^1]。 2. **FormData 字段名** 后端接收字段名需前后一致: ```javascript // Java 示例 (@RequestParam("files")) [^3] formData.append(&#39;files&#39;, file.raw); // 单文件场景 formData.append(&#39;file&#39;, file.raw); ``` 3. **请求传递方式** - 必须使用 `data` 传递 FormData,使用 `params` 无效 [^5] - 请求头建议设为 `&#39;Content-Type&#39;: undefined` 或 `&#39;multipart/form-data&#39;`,由浏览器自动添加 boundary [^4] 4. **后端接口要求** 需支持 `multipart/form-data` 格式,示例: ```java @PostMapping("/upload") public void upload(@RequestParam("files") MultipartFile[] files) {...} [^3] ``` ### 完整工作流程 1. 用户选择图片 → 触发 `on-change` 存入 `fileList` 2. 点击上传按钮 → 遍历 `fileList` 提取 `.raw` 文件 3. 构造 FormData → 通过 axios 的 `data` 字段发送 4. 后端接收二进制数组处理 ### 常见问题解决 - **文件流缺失**:检查是否使用了 `file.raw` 而非组件对象[^1][^4] - **请求无效**:确认使用 `data: formData` 而非 `params`[^5] - **跨域问题**:后端需配置 `Access-Control-Allow-Origin` - **文件大小限制**:可在 `before-upload` 钩子中添加校验 > 该方法适用于图片/文件上传场景,前端传递二进制流时可结合其他表单参数[^2][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

W.Y.B.G

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值