微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

结合el-upload组件实现大文件分片上传功能

前情提要

Element UI的el-upload上传组件相信各位小伙伴都已经非常熟悉,最近接了一个新需求,要求在el-upload组件基础上实现分片上传功能,即小于等于5M文件正常上传,大于5M文件切成5M每片上传。那么这个功能怎么实现呢?一起看看吧

代码实现

首先,我们需要设置el-upload组件的http-request,这样可以覆盖认的上传行为,可以自定义上传的实现。

<!-- data是上传时附带的额外参数,uploadFile是覆盖上传方法 -->
<el-upload :data="data" :http-request="uploadFile">
    <el-button icon="el-icon-upload2">本地文件</el-button>
</el-upload>

接下来,uploadFile方法中需要区分文件是否超过5M

async uploadFile({ data,file }) {
  // data是上传时附带的额外参数,file是文件
  let url = "xxx" //上传文件接口
  let loadingInstance = Loading.service({
    text: "正在上传文件,请稍后...",});
  try {
    // 如果文件小于5MB,直接上传
    if (file.size < 5 * 1024 * 1024) {
      let formData = new FormData();
      for (let key in data) {
        formData.append(key,data[key]);
      }
      formData.append("file",file);

      const res = await upload(url,formData);
      loadingInstance.close();
      return res;
    } else {
      // 如果文件大于等于5MB,分片上传
      data.file = file;
      const res = await uploadByPieces(url,data);
      loadingInstance.close();
      return res;
    }
  } catch (e) {
    loadingInstance.close();
    return e;
  }
}

upload方法就是正常上传方法,uploadByPieces是分片上传方法,我们可以把它们一个单独的js文件中,方便我们使用。

upload方法

const upload = (url,data,headers = {}) => {
    return new Promise((resolve,reject) => {
        axios({
            url,method: "post",headers: {
                ...headers,'Content-Type': 'multipart/form-data'
            }
        }).then(res => {
            return resolve(res.data)
        }).catch(err => {
            return reject(err)
        })
    })
}

在uploadByPieces方法中我们可以使用file.slice对文件进行切片

// 上传过程中用到的变量
const chunkSize = 5 * 1024 * 1024; // 5MB一片
const chunkCount = Math.ceil(file.size / chunkSize); // 总片数
// 获取当前chunk数据
const getChunkInfo = (file,index) => {
    let start = index * chunkSize;
    let end = Math.min(file.size,start + chunkSize);
    let chunk = file.slice(start,end);
    return { start,end,chunk };
};

File对象没有定义任何方法,但它从Blob对象中继承了slice方法:MDN

完整代码

upload.vue

<template>
    <el-upload :data="data" :http-request="uploadFile">
        <el-button icon="el-icon-upload2">文件上传</el-button>
    </el-upload>
</template>
<script>
// 引入上传文件方法
import { upload,uploadByPieces } from "@/utils/upload.js";
// Loading
import { Loading } from "element-ui";

export default {
    props: ["data"],methods: {
        async uploadFile({ data,file }) {
          // data是上传时附带的额外参数,file是文件
          let url = "xxx" //上传文件接口
          let loadingInstance = Loading.service({
            text: "正在上传文件,请稍后...",});
          try {
            // 如果文件小于5MB,直接上传
            if (file.size < 5 * 1024 * 1024) {
              let formData = new FormData();
              for (let key in data) {
                formData.append(key,data[key]);
              }
              formData.append("file",file);

              const res = await upload(url,formData);
              loadingInstance.close();
              return res;
            } else {
              // 如果文件大于等于5MB,分片上传
              data.file = file;
              const res = await uploadByPieces(url,data);
              loadingInstance.close();
              return res;
            }
          } catch (e) {
            loadingInstance.close();
            return e;
          }
        }
    }
}
</script>

upload.js

import axios from "axios";
//正常上传
const upload = (url,'Content-Type': 'multipart/form-data'
            }
        }).then(res => {
            return resolve(res.data)
        }).catch(err => {
            return reject(err)
        })
    })
}
//分片上传
const uploadByPieces = async (url,{ fileName,file }) => {
    // 上传过程中用到的变量
    const chunkSize = 5 * 1024 * 1024; // 5MB一片
    const chunkCount = Math.ceil(file.size / chunkSize); // 总片数
    // 获取当前chunk数据
    const getChunkInfo = (file,index) => {
        let start = index * chunkSize;
        let end = Math.min(file.size,start + chunkSize);
        let chunk = file.slice(start,end);
        return { start,chunk };
    };
    // 分片上传接口
    const uploadChunk = (data) => {
        return new Promise((resolve,reject) => {
            axios({
                url,headers: {
                    'Content-Type': 'multipart/form-data'
                }
            }).then(res => {
                return resolve(res.data)
            }).catch(err => {
                return reject(err)
            })
        })
    }
    // 针对单个文件进行chunk上传
    const readChunk = (index) => {
        const { chunk } = getChunkInfo(file,index);
        let fetchForm = new FormData();
        fetchForm.append("chunk",chunk);
        fetchForm.append("index",index);
        fetchForm.append("chunkCount",chunkCount);
        return uploadChunk(fetchForm)
    };
    // 针对每个文件进行chunk处理
    const promiseList = []
    try {
        for (let index = 0; index < chunkCount; ++index) {
                promiseList.push(readChunk(index))
        }
        const res = await Promise.all(promiseList)
        return res
    }catch (e) {
        return e
    }
}

export { upload,uploadByPieces }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐