广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >Vue实现封装一个切片上传组件
  • 949
分享到

Vue实现封装一个切片上传组件

Vue封装切片上传组件Vue切片上传组件Vue切片上传 2023-03-19 17:03:45 949人浏览 薄情痞子
摘要

目录组件效果使用文档封装过程1. 文件切片2. 构造切片请求参数3. 控制分片请求的并发完整代码待完善组件效果 单文件切片上传 多文件切片上传 组件使用案例 <templa

组件效果

单文件切片上传

多文件切片上传

组件使用案例

<template>
  <div id="app">
    <div class="upload-wrap">
      <UploadSlice
        :action="uploadInfoSlice.actionChunk"
        :headers="uploadInfoSlice.headers"
        :limit="uploadInfoSlice.limit"
        :accept="uploadInfoSlice.accept"
        :show-file-list="false"
        cancelable
        :on-success="handleSuccess"
        :on-remove="handleRemove"
        :on-cancel="handleCancel"
        :on-upload-pre="handleUploadPre"
        :on-upload-merge="handleUploadMerge"
        :on-fORM-data="genFormData"
      />
    </div>
  </div>
</template>

<script>
import UploadSlice from './components/UploadSlice.Vue'
import { uploadPre, uploadMerge } from '@/api/upload-slice'

export default {
  name: 'App',
  components: {
    UploadSlice
  },
  data() {
    return {
      // 上传部分
      uploadInfoSlice: {
        actionChunk: process.env.VUE_APP_BASE_API + '/storage/file/v3/chunk', // 切片请求上传路径
        headers: { 'Authorization': 'Bearer XXX' }
      }
    }
  },
  methods: {
    // 分片预请求
    async handleUploadPre(file) {
      const form = new FormData()
      form.append('fileSource', 'APPLICATION')
      form.append('originFileName', file.name)
      let res = ''
      try {
        res = await uploadPre(form)
      } catch (error) {
        throw new Error(error)
      }
    },
    // 构造分片参数
    genFormData(chunks, uid) {
      const prepareId = this.getCurrentPrepareId(uid)
      return chunks.map(chunk => {
        const form = new FormData()
        form.append('chunk', chunk.file)
        form.append('uploadId', prepareId)
        form.append('partNumber', chunk.index)
        return form
      })
    },
    // 合并请求
    async handleUploadMerge(file, uid) {
      const prepareId = this.getCurrentPrepareId(uid)
      const form = new FormData()
      form.append('fileSource', 'APPLICATION')
      form.append('hash', prepareId)
      form.append('filename', file.name)
      // return 建议使用, 用于handleSuccess获取数据
      try {
        const res = await uploadMerge(form)
        return res
      } catch (error) {
        return error
      }
    },
    // 判断当前处理prepareId
    getCurrentPrepareId(uid) {
      for (const item of this.progressFileList) {
        if (item.uid === uid) {
          return item.prepareId
        }
      }
    }
  }
}
</script>

使用文档

Attribute

标红色部分为二次封装处理过的功能,其他为el-upload自带属性

参数说明类型可选值默认值备注
action必选参数,分片上传的地址,预请求和合并请求在组件外操作String--
headers设置上传的请求头部String--
multiple是否支持多选文件boolean-
accept可上传文件类型,多种类型用","分隔 (格式不符合自动提示)String--
on-remove文件列表移除文件时的钩子function(file, fileList)
on-success文件上传成功时的钩子function(response, file, fileList)
on-error文件上传失败时的钩子function(err, file, fileList)
on-progress文件上传时的钩子function(event, file, fileList)
on-change文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用function(file, fileList)
on-exceed文件超出个数限制时的钩子function(files, fileList)
list-type文件列表的类型stringtext/picture/picture-cardtext
show-file-list是否显示已上传文件列表(文件分片上传时建议设置false,否则会有两个进度条)booleantrue
file-list上传的文件列表, 例如: [{name: 'food.jpg', url: 'xxx.cdn.com/xxx.jpg'}]array[]
disabled是否禁用booleanfalse
cancelable是否支持取消booleanfalse
limit最多允许上传个数(超出个数自动提示)number
size限制大小String
hideBtn是否在上传过程中隐藏上传按钮booleanfalse

Slot

插槽名说明
trigger触发文件选择框的内容
tip提示说明文字
more-tips在默认提示后补充说明

封装过程

切片上传组件是基于el-upload进行的二次封装,文章开头组件效果演示可以看到上传一个文件会发送三个请求:prepare,chunk, merge,也就是整个上传过程,主要分为三步:1.预请求 2.分片请求 3.合并请求,预请求和合并请求就是我们正常的Http请求,主要处理的是分片请求,分片请求主要的步骤是:

  • 将文件切片
  • 构造切片请求参数
  • 控制分片请求的并发

1. 文件切片

el-upload上传后, 在on-change属性的回调里可以获取文件file,通过file.raw.slice对文件进行切片,目前的切片规则是:1.小于10M 固定一片 2.小于50M 文件10%为一片 3.大于50M 固定5M 一片(可以根据自己的需求进行修改)

genFileChunks(file) {
  const chunks = []
  let cur = 0
  // 小于10M 固定一片
  if (file.size < (10 * 1024 * 1024)) {
    chunks.push({
      index: cur,
      file: file.raw.slice(cur, file.size),
      originFilename: file.name
    })
    return chunks
  }
  // 小于50M 文件10%为一片
  if (file.size < (50 * 1024 * 1024)) {
    const chunkSize = parseInt(file.size * 0.1)
    while (cur < file.size) {
      chunks.push({
        index: cur,
        file: file.raw.slice(cur, cur + chunkSize),
        originFilename: file.name
      })
      cur += chunkSize
    }
    return chunks
  }
  // 大于50M 固定5M 一片
  const chunkSize = parseInt(5 * 1024 * 1024)
  while (cur < file.size) {
    chunks.push({
      index: cur,
      file: file.raw.slice(cur, cur + chunkSize),
      originFilename: file.name
    })
    cur += chunkSize
  }
  return chunks
},

一个32M的文件按照10%切一片,构造好的切片数据是这样的

2. 构造切片请求参数

切片请求不同业务的参数是变化的,所以参数部分可以抛出给父组件处理,增加组件的复用性

父组件

<template>
  <UploadSlice
    :action="uploadInfoSlice.actionChunk"
    :headers="uploadInfoSlice.headers"
    :on-form-data="genFormData"
  />
</template>

<script>
  methods: {
    // 构造分片参数
    genFormData(chunks, uid) {
      const prepareId = this.getCurrentPrepareId(uid)
      return chunks.map(chunk => {
        const form = new FormData()
        form.append('chunk', chunk.file)
        form.append('uploadId', prepareId)
        form.append('partNumber', chunk.index)
        return form
      })
    },
  },
</script>

子组件

<template>
  <el-upload
      action=""
      :accept="accept"
  >
</template>

<script>
  props: {
    onFormData: {
      type: Function,
      default: () => {}
    },
  },
  methods: {
    async uploadChunks(uid) {
      // 预请求
      // ---------------

      // 上传切片
      const requests = this._genRequest(this._genUploadData(uid), uid)
      // 控制并发
      await this.sendRequest(requests)
      
      // 合并请求
      // ---------------
    },
    
    // 构造分片参数
    _genUploadData(uid) {
      const chunks = this.getCurrentChunks(uid)
      return this.onFormData(chunks, uid)
    },
    
    // 生成调用请求:[Promise, Promise]
    _genRequest(uploadData, uid) {
      console.log('uploadData', uploadData)
      const file = this.getCurrentFile(uid)
      const chunks = this.getCurrentChunks(uid)
      return uploadData.map((form, index) => {
        const options = {
          headers: this.$attrs.headers,
          file: file,
          data: form,
          action: this.action,
          onProgress: progress => {
            chunks[index].progress = Number(
              ((progress.loaded / progress.total) * 100).toFixed(2)
            )
            this.handleProgress(progress, file, uid)
          }
        }
        return options
      })
    },
  },
</script>

3. 控制分片请求的并发

切片上传如果不控制并发,在分片很多时,就会同时发送很多个http请求,导致线程阻塞,影响页面其他请求的操作,所以控制并发是需要的。我设置的是最多允许3个并发请求。

    sendRequest(requests, limit = 3) {
      return new Promise((resolve, reject) => {
        const len = requests.length
        let counter = 0
        let isTips = false // 只提示一次失败
        let isStop = false // 如果一个片段失败超过三次 认为当前网洛有问题 停止全部上传
        const startRequest = async() => {
          if (isStop) return
          const task = requests.shift()
          if (task && task.file.status !== 'cancel') {
            // 利用try...catch捕获错误
            try {
              // 具体的接口  抽离出去了
              await ajax(task)
              if (counter === len - 1) { // 最后一个任务
                resolve()
              } else { // 否则接着执行
                counter++
                startRequest() // 启动下一个任务
              }
            } catch (error) {
              // 网络异常
              if (error === 'NETWORK_ERROR' && !isTips) {
                Message.error('网络异常,文件上传失败')
                this.upLoading = false
                this.preLoading = false
                isTips = true
                this.handleRemove('', [])
              }

              // 接口报错重试,限制为3次
              if (task.error < 3) {
                task.error++
                requests.unshift(task)
                startRequest()
              } else {
                isStop = true
                reject(error)
              }
            }
          }
        }
        // 启动任务
        while (limit > 0) {
          // 模拟不同大小启动
          setTimeout(() => {
            startRequest()
          }, Math.random() * 2000)
          limit--
        }
      })
    }
  }

完整代码

文章只整理了核心代码,对于格式数量限制、进度条处理、取消上传等操作也进行了封装,详细请看完整代码

https://GitHub.com/Xmengling/el-upload-slice

待完善

  • 目前还没有做断点续传的处理
  • 可能还有一些异常边界情况没有考虑完整

到此这篇关于Vue实现封装一个切片上传组件的文章就介绍到这了,更多相关Vue封装切片上传组件内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Vue实现封装一个切片上传组件

本文链接: https://www.lsjlt.com/news/200245.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Vue实现封装一个切片上传组件
    目录组件效果使用文档封装过程1. 文件切片2. 构造切片请求参数3. 控制分片请求的并发完整代码待完善组件效果 单文件切片上传 多文件切片上传 组件使用案例 <templa...
    99+
    2023-03-19
    Vue封装切片上传组件 Vue切片上传组件 Vue切片上传
  • Vue如何实现封装一个切片上传组件
    今天小编给大家分享一下Vue如何实现封装一个切片上传组件的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。组件效果单文件切片上传...
    99+
    2023-07-05
  • vue-upload-component如何封装一个图片上传组件
    这篇文章主要介绍了vue-upload-component如何封装一个图片上传组件,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。需求分析业务...
    99+
    2022-10-19
  • vue封装组件之上传图片组件
    本文实例为大家分享了vue上传图片组件的封装具体代码,供大家参考,具体内容如下 未上传状态 上传状态 其他状态(查看/删除) 自定义组件文件名称 - 这里叫UploadImg....
    99+
    2022-11-12
  • vue-cropper插件实现图片截取上传组件封装
    基于vue-cropper插件实现图片截取上传组件封装的具体代码,供大家参考,具体内容如下 需求场景: 后台开发需要上传图片并进行相应比例尺寸图片的截取,本组件开发采用Ant Des...
    99+
    2022-11-12
  • vue-cropper组件实现图片切割上传
    本文实例为大家分享了vue-cropper组件实现图片切割上传的具体代码,供大家参考,具体内容如下 这几日,等来了些空闲,用vue和spring boot实践一次头像上传,因此记下...
    99+
    2022-11-12
  • vue中怎么实现一个上传图片组件
    本篇文章给大家分享的是有关vue中怎么实现一个上传图片组件,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1.首先得有一个[type=file]...
    99+
    2022-10-19
  • vue-cropper插件如何实现图片截取上传组件封装
    小编给大家分享一下vue-cropper插件如何实现图片截取上传组件封装,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!需求场景:后台开发需要上传图片并进行相应比例尺寸图片的截取,本组件开发采用Ant Design Vue组...
    99+
    2023-06-15
  • vue-cropper组件如何实现图片切割上传
    小编给大家分享一下vue-cropper组件如何实现图片切割上传,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!vue-cropper在vue中的引入1、组件内引入...
    99+
    2023-06-15
  • Vue中图片上传组件封装-antd的a-upload二次封装的实例
    目录图片上传组件封装-antd的a-upload二次封装api组件封装使用优化图片上传组件封装-antd的a-upload二次封装 a-upload组件 api const pub...
    99+
    2022-11-13
  • 怎么用Vue组件封装上传图片和视频
    这篇文章主要介绍“怎么用Vue组件封装上传图片和视频”,在日常操作中,相信很多人在怎么用Vue组件封装上传图片和视频问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么用Vue组件封装上传图片和视频”的疑惑有所...
    99+
    2023-06-20
  • vue如何实现文件切片上传
    这篇文章主要介绍了vue如何实现文件切片上传的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇vue如何实现文件切片上传文章都会有所收获,下面我们一起来看看吧。在实际开发项目过程中有时候需要上传比较大的文件,然后呢...
    99+
    2023-07-05
  • vue 文件切片上传的项目实现
    目录流程简说获取文件的 MD5 唯一标识码文件切片获取文件名 name分片文件大小 chunkSize文件切片 chunkList 列表切片总数 chunks切片大小 size合并在...
    99+
    2023-03-24
    vue 文件切片上传 vue 大文件上传
  • Vue组件封装上传图片和视频的示例代码
      首先下载依赖: cnpm i -S vue-uuid ali-oss 图片和视频字段都是数组类型,保证可以上传多个文件。 UploadImageVideo: &...
    99+
    2022-11-12
  • 浅析vue怎么实现文件切片上传
    在实际开发项目过程中有时候需要上传比较大的文件,然后呢,上传的时候相对来说就会慢一些,so,后台可能会要求前端进行文件切片上传,很简单哈,就是把比如说1个G的文件流切割成若干个小的文件流,然后分别请求接口传递这个小的文件流。流程简说实现文件...
    99+
    2023-05-14
    文件上传 文件切片 Vue.js
  • 基于Vue实现封装一个虚拟列表组件
    目录组件效果属性插槽封装过程滚动条正常显示加载渲染大量数据不卡顿能对列表数据进行操作增删等完整代码待完善正常情况下,我们对于数据都会分页加载,最近项目中确实遇到了不能分页的场景,如果...
    99+
    2023-03-07
    Vue封装虚拟列表组件 Vue 虚拟列表组件 Vue 虚拟列表
  • vue如何实现上传图片组件
    这篇文章给大家分享的是有关vue如何实现上传图片组件的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。未上传状态上传状态其他状态(查看/删除)自定义组件文件名称 - 这里叫UploadImg.vue<templ...
    99+
    2023-06-25
  • 开发一个封装iframe的vue组件
    目录一、组件介绍 二、组件内部结构及逻辑 1、代码组织结构2、地图组件三、iframe接口 四、外部接口 五、运行结果六、总结 VUE的基本组成单元,我看应该是组件。用VUE开发前端...
    99+
    2022-11-11
  • vue封装一个弹幕组件详解
    目录前言功能实现1、获取随机颜色随机数生成随机颜色编码生成2、随机生成弹幕出现的高度坐标3、格式化弹幕对象颜色定位4、创建弹幕对象滚动动画定义创建弹幕dom对象实例弹幕销毁弹幕循环5...
    99+
    2022-11-13
    vue封装弹幕组件 vue封装组件
  • vue文件切片上传的项目怎么实现
    这篇文章主要介绍“vue文件切片上传的项目怎么实现”,在日常操作中,相信很多人在vue文件切片上传的项目怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”vue文件切片上传的项目怎么实现”的疑惑有所帮助!...
    99+
    2023-07-05
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作