记录一次项目中用到的大文件分片上传vue解决实例如下

首先是封装的请求方法(文件...Sentlas.js部分内容)如下:

这里加了上传进度展示,请求包和数据包主体展示,所以传入了回调及vue实体

import axios from 'axios'

const Sentlas = {
    // ...放置了axios方法和具体的请求方法
    uploadFragmentResourceFile: function(data) {
    this.beforeRequest()
    return this.request({
      url: '...',
      params: { token: this.Token },
      method: 'post',
      data
    })
  },
}

/**
 * 上传资源文件(分片)
 * @param {File} file
 * @param {String|null} fileName
 * @param {Function|null} callback
 * @param {Object} vm
 * @returns
 */
export function uploadFragmentResourceFile(file, fileName = null, callback = null, vm = null) {
  if (file instanceof File) {
    if (fileName == null) {
      fileName = file.name // 文件名
    }

    var size = file.size // 文件大小
    var shardSize = 1024 * 1024 * 4 // 分片大小,这里设置4M
    var shardCount = Math.ceil(size / shardSize) // 分片数量

    var slice = function(f, inx) {
      // 容错
      if (inx >= shardCount) return

      // 计算偏移量
      var start = inx * shardSize
      var end = start + shardSize

      // 文件进行切片
      var packet = f.slice(start, end)
      var formData = new FormData()
      formData.append('file', packet, fileName)
      formData.append('fileName', fileName)
      formData.append('subId', inx)
      formData.append('total', shardCount)

      return Sentlas.uploadFragmentResourceFile(formData).then(r => {
        if (r.code === 20010) {
          // 继续上传
          if (typeof callback === 'function') {
            callback(vm, inx, shardCount, formData, r)
          }
          return slice(file, inx + 1)
        } else if (r.code === 20000) {
          // 成功
          if (typeof callback === 'function') {
            callback(vm, inx, shardCount, formData, r)
          }
          return Promise.resolve(r)
        } else {
          // 有错误
          console.log(r.msg)
          return slice(file, inx)
        }
      })
    }
    return slice(file, 0)
  } else {
    console.log('不是标准文件对象.')
    return Promise.resolve('不是标准文件对象.')
  }
}

vue文件:

<template slot="title">
  <div>
    <b>上传资源文件(分片)</b>
    <div>
      <el-form ref="api3form" :model="api3Data" size="mini" label-width="auto">
        <el-form-item label="选择文件">
          <input ref="clearFile3" type="file" @change="getFile3($event)">
        </el-form-item>
        <div>
          <el-progress
            :text-inside="true"
            :stroke-width="18"
            :percentage="f3progress"
          />
        </div>
      </el-form>
    </div>
    <div style="padding: 1em">
      <el-button
        size="mini"
        type="primary"
        round
        @click="api3()"
      >发送请求</el-button>
    </div>
  </div>
</template>
<script>
import { uploadFragmentResourceFile } from '@/utils/Sentlas'
export default {
  data() {
    return {
      files3: [],
      f3progress: 0,
      api3Data: {}
    }
  },
  methods: {
    api3: function() {
      if (this.files3.length !== 1) {
        this.$message('请先选择文件')
        return false
      }
      if (this.recvClean) this.cleanMessage()
      var file = this.files3[0]
      var fileName = file.name
      this.writeNews(
        1,
        this.api3Data,
        '上传资源文件(分片): POST /cgi-bin/upload-fragment-resource-file?token=...'
      )
      var vm = this
      uploadFragmentResourceFile(
        file,
        fileName,
        function(vmer, inx, total, request, response) {
          vmer.f3progress = Math.round((100 * (inx + 1)) / total)
          var object = {}
          request.forEach(function(value, key) {
            if (value instanceof File) {
              object[key] = '文件二进制数据...'
            } else {
              object[key] = value
            }
          })
          vmer.writeNews(1, object)
          vmer.writeNews(0, response)
        },
        vm
      )
    }
  }
}
</script>

上边仅贴出了部分代码,

由于时间仓促,错误与疏忽之处在所难免,希望各位朋友们以邮件的形式反馈问题给我,再次表示感谢!