通过el-upload封装一个可以分片上传大文件的组件

用到的插件只有el-upload和 spark-md5

<template>
    <div>
      <el-upload
      :action="dataUrl"
      accept=".gz"
      :on-change="handleBeforeUpload"
      :on-progress="handleUploadProgress"
      :on-success="handleUploadSuccess"
      :on-error="handleUploadError"
      :file-list="fileList"
      :on-remove="handleRemove"
      :data="uploadData"
      :headers="uploadHeaders"
      :limit="1"
      :multiple="false"
      :show-file-list="true"
      :auto-upload="false"
      :disabled="uploading"
      :with-credentials="true"
      :on-exceed="handleUploadExceed"
    >
     
      <div class="down_harbor">
        <i class="el-icon-top icon"></i>
        <el-button size="small"  :disabled="uploading" type="text">
        {{ uploading ? "镜像文件上传..." : "镜像文件上传" }}
      </el-button>
            </div>
    </el-upload>
      <el-progress :percentage=progressPercentage v-if="uploading"></el-progress>
    </div>
    
    
  </template>
  
  <script>
  import request from "@/utils/request";
  import { getFileMd5 } from "../../toolChain/lora/chunkFile.js";
  export default {
    props: {
        name:{
            type:String,
            default:''
        },
        tag:{
            type:String,
            default:''
        }
    },
    data() {
      return {
        fileSize:'',
        uploading: false,
        fileList: [],
        uploadData: {},
        md5: null,
        dataUrl: `${process.env.VUE_APP_BASE_API}/file/mirror/breakpoint-upload`,
        uploadHeaders: {},
        chunkSize: 5 * 1024 * 1024, // 5MB
        maxFileSize: 1000000 * 1024 * 1024, // 1000000MB
        progressPercentage: 0
      };
    },
    methods: {
      //上传之前
      async handleBeforeUpload(file) {
        this.fileSize=file.size
        this.md5 = await getFileMd5(
          new Blob([file], { type: file.type }),
          Math.ceil(file.size / this.chunkSize)
        );
        if (file.size > this.maxFileSize) {
          this.$message.error(
            `文件大小不能超过 ${this.maxFileSize / 1024 / 1024}MB.`
          );
          return false;
        }
        this.checkfile(file)
        this.fileList.push(file);
        await this.handleUpload(file);
        return false;
      },
      //检查文件是否已经上传
      checkfile(file) {
        request({
          url: `/file/mirror/check-file?fileName=${file.name}&&md5=${this.md5}&&name=${this.name}&&tag=${this.tag}`,
          method: "get",
        })
          .then((res) => {
            if (res.code == 200 && res.msg == "文件已上传成功") {
              this.$message.success("文件上传成功.");
              return;
            } else if (
              res.code == 200 &&
              res.msg == "检查到文件不存在,需要上传!"
            ) {
              this.checkfile(file);
              this.fileList.push(file);
              this.handleUpload(file);
            }
          })
          .catch((err) => {});
      },
      //删除已上传的文件
      handleRemove(file) {
        this.fileList=this.fileList.filter(item => item.name!=file.name)
      },
      //文件上传成功
      async handleUploadSuccess(response, file) {
        this.$emit("loadfile",this.fileList);
        this.uploading = false;
        this.$message.success("文件上传成功.");
      },
      //文件上传失败
      handleUploadError(error, file) {
        this.uploading = false;
        this.$message.error(`文件上传失败`);
      },
      //进度条
      handleUploadProgress(event, file, fileList) {
        const progress = Math.round(event.percent);
        file.progress = progress;
        this.fileList = [...fileList];
        this.progressVisible = true;
      },
      //文件超出个数限制时的钩子
      handleUploadExceed(files, fileList) {
        this.$message.error(`一次只能上传一个文件.`);
      },
      // 上传
      async uploadChunks(file) {
        const fileSize = file.size;
        const chunksTotal = Math.ceil(fileSize / this.chunkSize); //分片总数
        const fileName = file.name;
        let chunksUploaded = 0;
        let chunks = [];
  
        for (let i = 0; i < chunksTotal; i++) {
          const start = i * this.chunkSize;
          const end = Math.min(fileSize, start + this.chunkSize);
          chunks.push({
            file: file.slice(start, end),
            index: i,
            start,
            end,
            size: end - start,
            uploaded: false,
          });
        }
        while (chunksUploaded < chunksTotal) {
          const chunk = chunks[chunksUploaded];
          if (!chunk.uploaded) {
            const formData = new FormData();
            formData.append("file", chunk.file);
            formData.append("id", this.md5); //id
            formData.append("md5", this.md5); //md5
            formData.append("chunk", chunk.index); //第几分片
            formData.append("chunks", chunksTotal); //总分片数量
            // formData.append("size", this.chunkSize); //文件大小
            formData.append("size", this.fileSize); //文件大小
            formData.append("name", fileName); //文件名
            formData.append("mirrorName", this.name); //镜像名称
            formData.append("tag", this.tag); //镜像版本
            try {
              const response = await this.uploadChunk(formData);
              if (response.code == 200) {
                chunk.uploaded = true;
                chunksUploaded++;
                const progress = Math.round((chunksUploaded / chunksTotal) * 100);
                file.progress = progress;
                this.fileList = [...this.fileList];
              } else {
                throw new Error(
                  `上传分片 ${chunk.index} 失败: ${response.statusText}`
                );
              }
            } catch (error) {
              return;
            }
          } else {
            chunksUploaded++;
          }
        }
      },
      //上传一片
      async uploadChunk(formData) {
        return new Promise((resolve, reject) => {
          this.uploadFile(formData)
            .then((response) => {
              if (response.code == 200 && response.result == 200 ) {
                const progress = Math.round(
                  (formData.get('chunk') / formData.get('chunks')) * 100
                );
                this.fileList[0].progress = progress;
                this.progressPercentage=progress
                this.fileList = [...this.fileList];
                resolve(response);
              } else if (response.code == 200 && response.result == 201 ) {
                this.progressPercentage=100
                this.handleUploadSuccess();
                reject();
              } else {
                reject(this.$message.error(response.msg));
              }
            })
            .catch((error) => {
              console.log(error);
              console.log("捕获到了错误");
              this.$message.error("上传失败!");
            });
        });
      },
      uploadFile(params) {
        return request({
          url: `/file/mirror/breakpoint-upload`,
          method: "post",
          data: params,
        });
      },
  
      async handleUpload(file) {
        this.uploading = true;
        this.$emit("isloading",true);
        await this.uploadChunks(file.raw);
      },
    },
  };
  </script>
  <style>
  .down_harbor {
      width: 221px;
      height: 66px;
      background: #eef4ff;
      border-radius: 4px;
      border: 1px solid #afceff;
      font-size: 14px;
      font-family: PingFangSC, PingFang SC;
      font-weight: 500;
      color: #4985f8;
      text-align: center;
      line-height: 66px;
  
     
    }
  </style>
  

md5

import SparkMD5 from 'spark-md5'

/**
 * 获取文件MD5唯一标识码
 * @param file
 * @returns {Promise<unknown>}
 */
export function getFileMd5(file, chunkCount) {
  return new Promise((resolve, reject) => {
    const blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice
    const chunks = chunkCount
    let currentChunk = 0
    const spark = new SparkMD5.ArrayBuffer()
    const fileReader = new FileReader()

    fileReader.onload = function(e) {
      spark.append(e.target.result)
      currentChunk++
      if (currentChunk < chunks) {
        loadNext()
      } else {
        const md5 = spark.end()
        resolve(md5)
      }
    }
    fileReader.onerror = function(e) {
      reject(e)
    }
    function loadNext() {
      const start = currentChunk * chunkSize
      let end = start + chunkSize
      if (end > file.size) {
        end = file.size
      }
      fileReader.readAsArrayBuffer(blobSlice.call(file, start, end))
    }
    loadNext()
  })
}
// 切片大小,自定义
export const chunkSize = 5 * 1024 * 1024

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
封装el-upload实现大文件上传,可以按照以下步骤进行操作: 1. 在el-upload组件中设置file-list属性为一个数组,用于存储上传成功的文件信息。 2. 创建一个方法用于处理上传文件。在这个方法中,使用FormData对象来创建一个文件表单对象,并将需要附加的参数添加到表单中。 3. 在el-upload组件中设置before-upload属性为一个方法,用于在上传文件之前进行文件格式的判断。在该方法中,可以通过获取文件的后缀名或其他方式来判断文件格式是否满足需求。 4. 在el-upload组件中设置action属性为上传文件的接口地址。 5. 在el-upload组件中设置on-success属性为一个方法,用于在文件上传成功后执行的操作。在该方法中,可以将上传成功的文件信息添加到file-list数组中。 下面是一个示例代码,演示了如何封装el-upload实现大文件上传: ```javascript <template> <el-upload :action="uploadUrl" :before-upload="beforeUpload" :on-success="onSuccess" :file-list="fileList" multiple > <el-button>选择文件</el-button> </el-upload> </template> <script> export default { data() { return { uploadUrl: '/api/upload', fileList: [] }; }, methods: { beforeUpload(file) { // 在这里进行文件格式的判断,例如判断文件后缀名 const validExtensions = ['.xlsx', '.xls']; const extension = file.name.slice(file.name.lastIndexOf('.')); if (!validExtensions.includes(extension)) { this.$message.error('文件格式不正确'); return false; } return true; }, onSuccess(response, file) { // 在这里处理文件上传成功后的操作,例如将上传成功的文件信息添加到fileList数组中 this.fileList.push(file); } } }; </script> ``` 在这个示例中,el-upload组件的action属性设置为/api/upload,表示上传文件的接口地址。before-upload属性绑定了一个方法beforeUpload,用于文件格式的判断。on-success属性绑定了一个方法onSuccess,用于文件上传成功后的操作。file-list属性绑定了一个数组fileList,用于存储上传成功的文件信息。 通过以上步骤,可以封装el-upload组件实现大文件上传,并在上传文件之前进行文件格式的判断。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [elemetUi 组件el-upload实现上传Excel文件的实例](https://download.csdn.net/download/weixin_38574410/13192019)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [vue+axios+el-upload实现文件上传(带参数):](https://download.csdn.net/download/weixin_38502290/14016804)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [温控器LORA传输项目(lora)](https://download.csdn.net/download/m0_58719994/88269625)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值