vue+elementui中el-upload组件上传文件时,修改文件名,不用FormData

本文介绍了一种在Element UI中修改上传文件扩展名的方法。通过关闭自动上传并利用File API创建带有新扩展名的文件对象,实现了后端特殊需求。文章提供了核心代码及注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

今天在开发的时候,后端突然提了一个需求,因为特殊的文件上传不进文件服务器,所以后端问我能不能上传的时候给加个扩展名,本着只要逻辑没问题,都可以通过代码实现的理念,我说:“可以“”,于是乎有了这篇文章。

一、看别人怎么做的

首先是去element官网逛了逛,发现也没有提供修改文件拓展名的方法,所以只能请求度娘了。
百度了一下,发现别人都是使用普通的文件上传方式,代码一大堆,在钩子函数beforeUpload中获取到上传的文件后,修改名字,然后转成FormData后再用axios调接口上传。
然后我就试了,结果没成功,没办法,只能自己动手,从组件底层来找方法了。这一试,就搞了半天,好在最后成功了。

二、自己做

最终代码如下(用element官网的例子改的)

<template>
  <el-upload
    ref='upload'
    drag
    :auto-upload="false"
    action="https://jsonplaceholder.typicode.com/posts/"
    :limit="1"
    :on-change="handleChange">
    <i class="el-icon-upload"></i>
    <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
  </el-upload>
</template>
<script>
  export default {
    props: {
      //添加文件扩展名
      extendName: {
        type: String,
        default: '.rar'
      }
    },
    data() {
      return {};
    },
    methods: {
      handleChange(file) {
        let fileName = file.name + this.extendName  // 如果可以上传多个文件,这里需要用fileList.forEach()处理
        let f = new File([file.raw],fileName,file.raw.type);
        f.uid = file.uid; // new File 没有uid属性,会导致组件底层报错,这里手动加上
        file.raw = f;  // 用f替换file的数据
        console.log(file.raw)
        this.$refs.upload.submit(); // 手动触发上传
      },
    }
  }
</script>

一次上传单个文件的核心代码不多,就几行。如果是上传多个文件就需要用fileList来的处理,这里就不写了

下面讲一下代码

  1. 首先得关闭组件的自动上传
  2. fileName就是我们最终要的文件名,这里的业务需求就是添加一个扩展名
  3. f是使用 new File创建的新的文件对象,在创建文件对象的时候给它新名字fileName(刚开始想的是,直接用file.raw.name = fileName 但是结果报错说name是只读属性,不能修改,所以这里使用new File创建新文件,然后整个替换掉raw)
  4. 这里的f.uid = file.uid是el-upload底层会用uid去匹配fileList数组中的文件,如果没有这个uid最后匹配返回的null会在底层报错。下面是源码位置:node_modules\element-ui\packages\upload\src\index.vue
    // 匹配
    getFile(rawFile) {
     let fileList = this.uploadFiles;
     let target;
     fileList.every(item => {
       target = rawFile.uid === item.uid ? item : null;
       return !target;
     });
     return target;
   },
   handleProgress(ev, rawFile) {
     const file = this.getFile(rawFile);
     this.onProgress(ev, file, this.uploadFiles);
     // 报错点 null没有status属性
     file.status = 'uploading';
     file.percentage = ev.percent || 0;
   },
  1. 更新file.raw为修改文件名后的文件对象
  2. 手动调用submit()上传文件

最终效果:
在这里插入图片描述

Vue+elementui分片上传可以使用如下步骤: 1. 前端将大文件分为若干个片段,并将每个片段上传到后端。 2. 后端将每个片段存储在服务器上,并返回每个片段的文件名和存储路径。 3. 前端将每个片段的文件名和存储路径组成一个数组,发送给后端。 4. 后端将数组中的每个片段按照顺序合并成一个完整的文件。 5. 前端可以在上传过程中显示上传进度,并支持暂停、恢复和取消上传。可以使用Vue+elementui+axios实现大文件分片上传。 以下是示例代码: ``` <template> <div> <el-upload ref="upload" :show-file-list="false" :on-change="handleChange" :before-upload="handleBeforeUpload" :on-progress="handleProgress" :on-success="handleSuccess" :on-error="handleError"> <el-button size="small" type="primary">点击上传</el-button> </el-upload> <el-progress :percentage="percent"></el-progress> <el-button-group> <el-button size="small" @click="handleStart">开始上传</el-button> <el-button size="small" @click="handlePause">暂停上传</el-button> <el-button size="small" @click="handleResume">恢复上传</el-button> <el-button size="small" @click="handleCancel">取消上传</el-button> </el-button-group> </div> </template> <script> import { ElUpload, ElButton, ElProgress, ElButtonGroup } from 'element-ui' import axios from 'axios' export default { components: { ElUpload, ElButton, ElProgress, ElButtonGroup }, data() { return { file: null, fileChunks: [], uploading: false, uploadedChunks: [], percent: 0, uploadUrl: 'https://www.example.com/upload', token: 'your_token', fileId: 'your_file_id', chunkSize: 1024 * 1024, // 每个片段的大小 maxRetries: 5, // 最大重试次数 } }, methods: { handleChange(file) { this.file = file this.fileChunks = this.getChunks(file) this.uploadedChunks = [] this.percent = 0 }, handleBeforeUpload(file) { // 阻止自动上传 return false }, handleStart() { if (!this.uploading) { this.uploading = true this.uploadChunks(this.fileChunks, 0) } }, handlePause() { this.uploading = false }, handleResume() { this.uploading = true this.uploadChunks(this.fileChunks, this.uploadedChunks.length) }, handleCancel() { this.file = null this.fileChunks = [] this.uploading = false this.uploadedChunks = [] this.percent = 0 }, handleProgress(event, file) { if (file === this.file) { this.percent = event.percent } }, handleSuccess(response, file) { if (file === this.file) { this.uploading = false console.log('上传成功') } }, handleError(error, file) { if (file === this.file) { this.uploading = false console.log('上传失败') } }, getChunks(file) { const fileSize = file.size const chunks = [] let start = 0 let end = this.chunkSize while (start < fileSize) { chunks.push({ file: file.slice(start, end), index: Math.ceil(start / this.chunkSize), retries: 0, uploaded: false, uploading: false, error: false, }) start = end end += this.chunkSize } return chunks }, async uploadChunks(chunks, start) { if (!this.uploading) { return } const maxIndex = chunks.length - 1 for (let i = start; i <= maxIndex; i++) { const chunk = chunks[i] if (chunk.uploaded || chunk.uploading) { continue } chunk.uploading = true const formData = new FormData() formData.append('chunkIndex', chunk.index) formData.append('chunkFile', chunk.file) formData.append('chunkSize', this.chunkSize) formData.append('fileId', this.fileId) formData.append('token', this.token) try { const response = await axios.post(this.uploadUrl, formData, { headers: { 'Content-Type': 'multipart/form-data', }, }) chunk.uploaded = true chunk.uploading = false this.uploadedChunks.push(chunk) console.log(`上传成功:${chunk.index}`) } catch (error) { chunk.uploading = false if (chunk.retries < this.maxRetries) { chunk.retries++ console.log(`上传失败,正在重试:${chunk.index}`) i-- } else { chunk.error = true console.log(`上传失败:${chunk.index}`) } } if (this.uploadedChunks.length === chunks.length) { this.mergeChunks(chunks) break } } }, async mergeChunks(chunks) { const formData = new FormData() formData.append('fileId', this.fileId) formData.append('token', this.token) try { const response = await axios.post(this.uploadUrl + '/merge', formData) console.log('合并成功') } catch (error) { console.log('合并失败') } }, }, } </script> ``` 以上代码中,`el-upload`组件用于选择文件和显示上传进度,`ElProgress`组件用于显示上传进度条,`ElButtonGroup`组件用于控制上传操作。`handleChange`方法用于获取文件,并将文件分成若干个片段。`handleBeforeUpload`方法用于阻止自动上传。`handleStart`方法用于开始上传。`handlePause`方法用于暂停上传。`handleResume`方法用于恢复上传。`handleCancel`方法用于取消上传。`handleProgress`方法用于更新上传进度。`handleSuccess`方法用于上传成功后的处理。`handleError`方法用于上传失败后的处理。`getChunks`方法用于将文件分成若干个片段。`uploadChunks`方法用于上传每个片段。`mergeChunks`方法用于将所有片段合并成一个完整的文件。 注意,在上传每个片段,需要使用`FormData`来上传文件。在上传成功后,需要将上传成功的片段保存在`uploadedChunks`数组中,并在所有片段都上传成功后,调用`mergeChunks`方法将所有片段合并成一个完整的文件。在上传过程中,可以使用`percent`属性来显示上传进度。在上传,可以支持暂停、恢复和取消上传操作。
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值