验证码: 看不清楚,换一张 查询 注册会员,免验证
  • {{ basic.site_slogan }}
  • 打开微信扫一扫,
    您还可以在这里找到我们哟

    关注我们

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

阅读:737 来源:乙速云 作者:代码code

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

      组件效果

      单文件切片上传

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

      多文件切片上传

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

      组件使用案例

      
      
      

      使用文档

      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%切一片,构造好的切片数据是这样的

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

      2. 构造切片请求参数

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

      父组件

      
      
      

      子组件

      
      
      

      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--
              }
            })
          }
        }
    分享到:
    *特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: hlamps#outlook.com (#换成@)。
    相关文章
    {{ v.title }}
    {{ v.description||(cleanHtml(v.content)).substr(0,100)+'···' }}
    你可能感兴趣
    推荐阅读 更多>