使用Vue3+ElementPlus前端实现分片上传的全过程

目录
  • 1. 什么是分片上传
  • 2. 上传组件模板
  • 3. 上传组件逻辑
    • 3.1 基本思路
    • 3.2 选择上传文件
    • 3.3 校验文件是否合法
    • 3.4 文件加密
    • 3.5 合并文件
    • 3.6 文件切片上传
  • 4. 参考文章
    • 4.1 文章链接
    • 4.2 参考文章提到的注意事项
      • 4.2.1 nginx 上传大小限制
      • 4.2.2 大文件下载
  • 总结

1. 什么是分片上传

将 一个文件 切割为 一系列特定大小的 数据片段,将这些 数据片段 分别上传到服务端;

全部上传完成后,再由服务端将这些 数据片段 合并成为一个完整的资源;

上传过程中,由于外部因素(比如网络波动)导致上传中断,下次上传时会保留该文件的上传进度(断点续传);

2. 上传组件模板

包含三部分:

  • 上传组件,使用 el-upload
  • 进度条组件,使用 el-progress
  • 上传完成状态组件,使用 el-input 自定义
 <el-form-item label="上传附件" prop="uploadFile">
   <el-upload
       v-if="!editForm.inlineAppVersionModel.fileName"
       class="upload-demo"
       drag
       :show-file-list="false"
       :action="APP_MANAGEMENT.uploadFile"
        // 根据项目的接口传递参数
       :data="{
         applicationId: applicationId,
         applicationVersion: applicationVersion,
         bucketName: 'app'
       }"
       // 覆盖默认的http请求
       :http-request="handleFileUpload"
   >
     <el-icon class="el-icon--upload">
       <upload-filled />
     </el-icon>

     <div v-if="!progress" class="el-upload__text">
       Drop file here or <em>click to upload</em>
     </div>

     // 进度条
     <el-progress
        v-else
        :text-inside="true"
        :stroke-width="24"
        :percentage="progress"
        status="success"
       />
   </el-upload>

   // 上传成功之后隐藏上传文件组件
   <div v-else style="display: flex;">
     <el-input v-model="editForm.inlineAppVersionModel.fileName" readonly>
     </el-input>
     <div style="display: flex;">
       <el-button
           type="primary"
           :icon="Download"
           size="small"
           @click="handleFileDownload"
          />
       <el-button type="primary" :icon="Delete" size="small" @click="handleFileDel" />
     </div>
   </div>
 </el-form-item>

3. 上传组件逻辑

3.1 基本思路

使用 el-upload 选择文件

选择成功的 回调函数 可以读取文件信息,用于前端校验文件的合法性

前端校验文件合法后,将文件进行切片

通过 请求轮询 把切片传递给后端

3.2 选择上传文件

在这一步,可以获得文件信息

根据文件信息,对文件进行合法性校验

校验成功后,调用文件切片方法

/**
 * @description: 选择上传文件
 * @param file el-upload 返回的参数
 */
const handleFileUpload = async (file: any) => {
  console.log('el-upload 返回的参数 === ', file.file);

  // 如果文件合法,则进行分片上传
  if (await checkMirrorFile(file)) {
    // 文件信息
    const files = file.file;
    // 从 0 开始的切片
    const shardIndex = 0;
    // 调用 文件切片 方法
    uploadFileSilce(files, shardIndex);
  // 文件非法,则进行提示
  } else {
    ElMessage.error('请检查文件是否合法!');
  }
};

3.3 校验文件是否合法

校验文件格式

校验文件大小

调用接口,校验磁盘剩余空间大小

/**
 * @description: 校验文件合法性
 */
const checkMirrorFile = async (file) => {
    // 校验文件格式,支持.zip/.tar
    const fileType = file.file.name.split('.')
    if (fileType[fileType.length - 1] !== 'zip' && fileType[fileType.length - 1] !== 'tar') {
        ElMessage.warning('文件格式错误,仅支持 .zip/.tar')
        return false
    }

    // 校验文件大小
    const fileSize = file.file.size;
    // 文件大小是否超出 2G
    if (fileSize > 2 * 1024 * 1024 * 1024) {
        ElMessage.warning('上传文件大小不能超过 2G')
        return false
    }

    // 调用接口校验文件合法性,比如判断磁盘空间大小是否足够
    const res = await checkMirrorFileApi()
    if (res.code !== 200) {
        ElMessage.warning('暂时无法查看磁盘可用空间,请重试')
        return false
    }
    // 查看磁盘容量大小
    if (res.data.diskDevInfos && res.data.diskDevInfos.length > 0) {
        let saveSize = 0
        res.data.diskDevInfos.forEach(i => {
            // 磁盘空间赋值
            if (i.devName === '/dev/mapper/centos-root') {
                // 返回值为GB,转为字节B
                saveSize = i.free * 1024 * 1024 * 1024
            }
        })
        // 上传的文件大小没有超出磁盘可用空间
        if (fileSize < saveSize) {
            return true
        } else {
            ElMessage.warning('文件大小超出磁盘可用空间容量')
            return false
        }
    } else {
        ElMessage.warning('文件大小超出磁盘可用空间容量')
        return false
    }
}

3.4 文件加密

此处文件上传用 MD5 进行加密,需要安装依赖 spark-md5

npm i spark-md5

/**
 * @description: 文件加密处理
 */
const getMD5 = (file: any): Promise<string> => new Promise((resolve, reject) => {
  const spark = new SparkMD5.ArrayBuffer();
  // 获取文件二进制数据
  const fileReader = new FileReader();
  fileReader.readAsArrayBuffer(file); // file 就是获取到的文件
  // 异步执行函数
  fileReader.addEventListener('load', (e: any) => {
    spark.append(e.target.result);
    const md5: string = spark.end();
    resolve(md5);
  });
  fileReader.addEventListener('error', (e) => {
    reject(e);
  });
});

3.5 合并文件

通过接口合并上传文件,接口需要的参数:

  • 文件名
  • 文件唯一 hash 值

接口合并完成后,前端展示已上传的文件名称

/**
 * @description: 合并文件
 * @param name 文件名
 * @param hash 文件唯一 hash 值
 * @return 命名名称
 */
const composeFile = async (name: string, hash: string) => {
  console.log('开始文件合并');
  const res = await uploadFileMerge({
    applicationId: props.applicationId,
    applicationVersion: props.applicationVersion,
    bucketName: 'app',
    fileName: name,
    hash,
  });
  console.log('后端接口合并文件 ===', res);
  if (res.status === 200 && res.data.code) {
    // 合并成功后,调整已上传的文件名称
    state.editForm.inlineAppVersionModel.fileName = name;
  }
};

3.6 文件切片上传

接口轮询 —— 每次携带一个文件切片给后端;后端接受到切片 并 返回成功状态码后,再进行下一次切片上传

/**
 * @description: 分片函数
 * @param file 文件
 * @param shardIndex 分片数量
 */
const uploadFileSilce = async (file: File, shardIndex: number) => {
      // 文件名
      const { name } = file;
      // 文件大小
      const { size } = file;
      // 分片大小
      const shardSize = 1024 * 1024 * 5;
      // 文件加密
      const hash: string = await getMD5(file);
      // 分片总数
      const shardTotal = Math.ceil(size / shardSize);

      // 如果 当前分片索引 大于 总分片数
      if (shardIndex >= shardTotal) {
        isAlive.value = false;
        progress.value = 100;
        // 合并文件
        composeFile(name, hash);
        return;
      }

      // 文件开始结束的位置
      const start = shardIndex * shardSize;
      const end = Math.min(start + shardSize, size);
      // 开始切割
      const packet = file.slice(start, end);

      // 拼接请求参数
      const formData = new FormData();
      formData.append('file', packet);
      formData.append('applicationId', props.applicationId);
      formData.append('applicationVersion', props.applicationVersion);
      formData.append('bucketName', 'app');
      formData.append('hash', hash);
      formData.append('shardSize', shardSize as unknown as string);
      formData.append('seq', shardIndex as unknown as string);

      // 如果 当前分片索引 小于 总分片数
      if (shardIndex < shardTotal) {
        // 进度条保留两位小数展示
        progress.value = Number(((shardIndex / shardTotal) * 100).toFixed(2)) * 1;
        // 调用文件上传接口
        const res = await uploadFile(formData);
        if (res.status !== 200) {
          ElMessage.error('上传失败');
          progress.value = 0;
          return;
        }
        if (res.status === 200 && res.data.code === 200) {
          // 这里为所有切片上传成功后进行的操作
          console.log('上传成功');
        }
        // eslint-disable-next-line no-param-reassign
        shardIndex++;
        // 递归调用 分片函数
        uploadFileSilce(file, shardIndex);
      }
    };

4. 参考文章

4.1 文章链接

前端大文件上传和下载(分片上传)

4.2 参考文章提到的注意事项

4.2.1 nginx 上传大小限制

nginx 默认上传大小为 1MB,若超过 1MB,则需要修改 nginx 配置 解除上传限制

4.2.2 大文件下载

/**
 * @description: 动态创建 a 标签,实现大文件下载
 */
const downloadMirror = async (item) => {
  let t = {
    id: item.id,
  }
  const res = await downloadMirrorApi(t)
  if (res.headers["content-disposition"]) {
    let temp = res.headers["content-disposition"].split(";")[1].split("filename=")[1]
    let fileName = decodeURIComponent(temp)
    // 通过创建a标签实现文件下载
    let link = document.createElement('a')
    link.download = fileName
    link.style.display = 'none'
    link.href = res.data.msg
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
  } else {
    ElMessage({
      message: '该文件不存在',
      type: 'warning',
    })
  }
}

总结

到此这篇关于使用Vue3+ElementPlus前端实现分片上传的文章就介绍到这了,更多相关Vue3+ElementPlus前端分片上传内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Vue3 + elementplus实现表单验证+上传图片+ 防止表单重复提交功能

    首先,上官网地址 https://element.eleme.cn/ 首先页面上面用了弹窗的形式,做完之后长这样,有全屏,关闭等按钮,上效果图和完整代码!!!!! <!--点击新增按钮 --> <div class="addbtn" @click="fundOperation()">   <span>+</span> 新增 </div> <el-dialog v-model="datadia

  • 利用Vue3和element-plus实现图片上传组件

    目录 前言 具体代码 图片上传 上传组件 前言 element-plus 提供了 uploader 组件,但是不好定制化,所以自己又造了个轮子,实现了一个图片上传的组件,它的预期行为是: 1.还没上传图片时,显示上传卡片 2.上传图片时显示进度条,隐藏上传卡片 3.上传成功时显示图片缩略图,上传失败则显示失败提示 4.支持上传图片的预览和删除 具体如下图所示: 具体代码 图片上传 这里使用的图床是牛图网,无需注册,貌似也没有图片大小的限制,但是请不要上传违规图像. <code>import a

  • 使用Vue3+ElementPlus前端实现分片上传的全过程

    目录 1. 什么是分片上传 2. 上传组件模板 3. 上传组件逻辑 3.1 基本思路 3.2 选择上传文件 3.3 校验文件是否合法 3.4 文件加密 3.5 合并文件 3.6 文件切片上传 4. 参考文章 4.1 文章链接 4.2 参考文章提到的注意事项 4.2.1 nginx 上传大小限制 4.2.2 大文件下载 总结 1. 什么是分片上传 将 一个文件 切割为 一系列特定大小的 数据片段,将这些 数据片段 分别上传到服务端: 全部上传完成后,再由服务端将这些 数据片段 合并成为一个完整的资

  • 利用Vue3+Element-plus实现大文件分片上传组件

    目录 一.背景 二.技术栈 三.核心代码实现 四.总结 一.背景 实际项目中遇到需要上传几十个G的3d模型文件,传统上传就不适用了. 结合element提供的上传组件自己封装了文件分片上传的组件. 思路: 把文件拆分成若干分片 依次上传分片(每次上传前可校验该分片是否已经上传) 发起合并分片的请求 二.技术栈 Vue3+Ts+Element-Plus 其他库:spark-md5 后端接口: 上传分片接口 校验分片是否已上传接口 合并分片接口 三.核心代码实现 Element组件基础配置 <el-

  • 前端大文件上传与下载(分片上传)的详细过程

    目录 一.问题 二.解决 1.第一步选择文件 2.校验文件是否符合规范 3.文件切片上传 4.分片上传注意点 5.大文件下载 总结 一.问题 日常业务中难免出现前端需要向后端传输大型文件的情况,这时单次的请求不能满足传输大文件的需求,就需要用到分片上传 业务需求为:用户可以上传小于20G的镜像文件,并进显示当前上传进度 前端:vue3.x+Element Plus组件+axios 二.解决 解决思路简单为前端选择文件后读取到文件的基本信息,包括:文件的大小.文件格式等信息,用于前端校验,校验完成

  • vue+element+oss实现前端分片上传和断点续传

    纯前端实现: 切片上传 断点续传 .断点续传需要在切上上传的基础上实现 前端之前上传OSS,无需后端提供接口.先上完整代码,直接复制,将new OSS里的参数修改成自己公司OSS相关信息后可用,如遇问题,请继续往下看. oss官方文档 https://help.aliyun.com/document_detail/111268.html?spm=a2c4g.11186623.6.1111.5a583a07LknRUO 代码允许所需环境:vue + element + ali-oss 安装ali-

  • 前端使用koa实现大文件分片上传

    目录 引言 前端 拆分上传的文件流 后端 接收文件片段 合并文件片段 总结 引言 一个文件资源服务器,很多时候需要保存的不只是图片,文本之类的体积相对较小的文件,有时候,也会需要保存音视频之类的大文件.在上传这些大文件的时候,我们不可能一次性将这些文件数据全部发送,网络带宽很多时候不允许我们这么做,而且这样也极度浪费网络资源. 因此,对于这些大文件的上传,往往会考虑用到分片传输. 分片传输,顾名思义,也就是将文件拆分成若干个文件片段,然后一个片段一个片段的上传,服务器也一个片段一个片段的接收,最

  • webuploader分片上传的实现代码(前后端分离)

    本文介绍了webuploader分片上传的实现代码(前后端分离),分享给大家,具体如下: WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件.在现代的浏览器里面能充分发挥HTML5的优势,同时又不摒弃主流IE浏览器,沿用原来的FLASH运行时,兼容IE6+,iOS 6+, android 4+.两套运行时,同样的调用方式,可供用户任意选用.采用大文件分片并发上传,极大的提高了文件上传效率.(这个是从官网上直接copy的

  • 基于Node.js的大文件分片上传示例

    我们在做文件上传的时候,如果文件过大,可能会导致请求超时的情况.所以,在遇到需要对大文件进行上传的时候,就需要对文件进行分片上传的操作.同时如果文件过大,在网络不佳的情况下,如何做到断点续传?也是需要记录当前上传文件,然后在下一次进行上传请求的时候去做判断. 先上代码:代码仓库地址 前端 1. index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8

  • PHP大文件分片上传的实现方法

    一.前言 在网站开发中,经常会有上传文件的需求,有的文件size太大直接上传,经常会导致上传过程中耗时太久,大量占用带宽资源,因此有了分片上传. 分片上传主要是前端将一个较大的文件分成等分的几片,标识当前分片是第几片和总共几片,待所有的分片均上传成功的时候,在后台进行合成文件即可. 二.开发过程中遇到的问题 分片的时候每片该分多大size?太大会出现"413 request entity too large" 分片上传的时候并不是严格按照分片的序号顺序上传,如何判断所有的分片均上传成功

  • spring boot如何实现切割分片上传

    这篇文章主要介绍了spring boot如何实现切割分片上传,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 文件上传是web开发中经常会遇到的 springboot的默认配置为10MB,大于10M的是传不上服务器的,需要修改默认配置 但是如果修改支持大文件又会增加服务器的负担. 当文件大于一定程度时,不仅服务器会占用大量内存,而且http传输极可能会中断. 可以采用切割分片上传 html5提供的文件API中可以轻松的对文件进行分割切片,然后通过

  • Vue.Js及Java实现文件分片上传代码实例

    说明 代码从项目中剥离修改,未经测试,仅提供思路. 前端 upload(file) { //从后台获取已经上传的文件分片数 getIdx(md5) .then(function(res) { let retry = 3; uploadPart(retry, file, res.data); }) .catch(); } uploadPart(retry, file, idx) { //设置分片大小(单位Byte) let bufferLength = 1024 * 1024 * 5; //计算开

随机推荐