当前位置: 首页 > 工具软件 > v-uploader > 使用案例 >

基于vue-simple-uploader 实现大文件分片上传(补充)

姜振濂
2023-12-01

前言

之前做了基于vue-simple-uploader大文件的大文件上传,目前新的需求是把音频也进行大文件形式上传,
那么上传的时候需要进行字段校验上传的文件是视频还是音频,本文将针对这一点进行操作

加入音频

1、我们通过选择框选择视频还是音频进行页面的显示,字段form.courseType,2是视频,3是音频
2、为uploader-btn标签添加id
3、注意不可以这么写
 <uploader-btn :attrs="form.courseType == 2?attrs:attrs1" v-show="false" ref="upload">选择{{form.courseType == 2?'视频':'音频'}}文件</uploader-btn>
 原因是还没等进行判断courseType 类型标签已经渲染结束,无法通过courseType 的改变进行动态渲染
<uploader
   ref="uploader1"
   :options="options"
   :file-status-text="fileStatusText"
   :autoStart="false"
   @upload-start="onUploadStart"
   @file-added="onFileAdded"
   @file-progress="onFileProgress"
   @file-success="onFileSuccess"
   @file-error="onFileError"
   class="uploader-example">
     <uploader-unsupport></uploader-unsupport>
       <!-- <p>Drop files here to upload or</p> -->
       <el-button size="small" @click="beforeUploade">点击上传</el-button>
       <div>{{form.courseType == 2?'只能上传mp4,mov,avi格式':'上传音频格式的文件'}}</div>
       <div v-show="form.courseType == 2">
         <uploader-btn :attrs="attrs" v-show="false" id="shipin" ref="upload">选择{{form.courseType == 2?'视频':'音频'}}文件</uploader-btn>
       </div>
       <div v-show="form.courseType == 3">
         <uploader-btn :attrs="attrs1" v-show="false" id="yinpin" ref="upload1">选择{{form.courseType == 2?'视频':'音频'}}文件</uploader-btn>
       </div>
       <!-- <uploader-btn :directory="true">select folder</uploader-btn> -->
     <uploader-list v-show="!form.videoUrl"></uploader-list>
     <div v-show="form.videoUrl">{{form.videoUrl}}</div>
   </uploader>
upload.js下
1、添加音频选择文件
2、上传前针对input的value置空,允许input框重复上传同一个文件
3、在onFileAdded(file)下做文件上传前的校验
 data(){
      return {
           // 文件上传参数
          uploaderInstance:undefined,
          options: {
            headers: { Authorization: "Bearer " + getToken() },
            // target: process.env.VUE_APP_BASE_API + "/file?type=1",
            target: process.env.VUE_APP_BASE_API + "/bigfile/upload",
            testChunks: false,
            chunkSize: 1024*1024*5,  //5MB
            simultaneousUploads: 3, //并发上传数
            maxChunkRetries: 2, //最大自动失败重试上传次数
            parseTimeRemaining: function (timeRemaining, parsedTimeRemaining) { //格式化时间
                return parsedTimeRemaining
                    .replace(/\syears?/, '年')
                    .replace(/\days?/, '天')
                    .replace(/\shours?/, '小时')
                    .replace(/\sminutes?/, '分钟')
                    .replace(/\sseconds?/, '秒')
            },
            testChunks: true,   //开启服务端分片校验
            // 服务器分片校验函数
            checkChunkUploadedByResponse: (chunk, message) => {
              let obj = JSON.parse(message);
              // console.log('sss',chunk,message,obj)
                if (obj.data.isExist=='true') {
                  console.log('aaa')
                    this.statusTextMap.success = '秒传文件,处理中····';
                    this.form.videoUrl = obj.data.url
                    return true;
                }
                // return (obj.uploaded || []).indexOf(chunk.offset + 1) >= 0
                return obj.data.uploaded >chunk.offset + 1
            },
          },
          statusTextMap: {
                success: '文件处理中···',
                error: '上传出错了',
                uploading: '上传中...',
                paused: '暂停',
                waiting: '等待中...',
                cmd5: '准备中...'
            },
          fileStatusText: (status, response) => {
              return this.statusTextMap[status];
          },
          attrs: {
            accept: 'video/*',
            // multiple: false,
            // multipleLimit:1
          },
   ++       attrs1: {
            accept: 'audio/*',
            // multiple: false,
            // multipleLimit:1
          },
      }
  },
beforeUploade(){
      // if(this.$refs.uploader1.files.length>1){
      //   console.log('文件列表1',this.$refs.uploader1.files,this.$refs.uploader1.fileList)
      //   // this.$refs.uploader1.files.shift()
      //   this.$refs.uploader1.uploader.cancel()
      //   // this.$refs.uploader1.uploader.pause(this.$refs.uploader1.files[0])
      //   // this.$refs.uploader1.uploader.removeFile(this.$refs.uploader1.files[0])
      //   // this.$refs.uploader1.uploader.fileRemoved(this.$refs.uploader1.files[0])
      // }
      // if(this.$refs.uploader1.fileList.length>1){
      //   console.log('文件列表2',this.$refs.uploader1.files,this.$refs.uploader1.fileList)
      //   this.$refs.uploader1.uploader.cancel()
      // }
      // document.querySelector('.uploader-btn>input').value=''
      // console.log('1111',this.$refs.uploader1.uploader.cancel)
      this.$refs.uploader1.uploader.cancel()
      this.form.videoUrl=''
      if(this.form.courseType == 2){
        document.querySelector('#shipin>input').nodeValue=''
        document.querySelector('#shipin>input').click()
      }else{
        document.querySelector('#shipin>input').nodeValue=''
        document.querySelector('#yinpin>input').click()
      }
    },
onFileAdded(file) { // 文件上传前的校验
      console.log(file)
      if(this.form.courseType == 2&&file.fileType.indexOf('video')==-1){
        console.log('上传的不是视频')
        this.form.videoUrl=''
        this.$message.warning(this.form.courseType == 2?'请上传正确的视频类型':'请上传正确的音频类型')
        setTimeout(() => {
          this.$refs.uploader1.uploader.removeFile(file)
        }, 0);
        return
      }
      if(this.form.courseType == 3&&file.fileType.indexOf('audio')==-1){
        console.log('上传的不是音频')
        this.form.videoUrl=''
        this.$message.warning(this.form.courseType == 2?'请上传正确的视频类型':'请上传正确的音频类型')
        setTimeout(() => {
          this.$refs.uploader1.uploader.removeFile(file)
        }, 0);
        return
      }
      this.computeMD5(file);
    },
注意:
 setTimeout(() => {
    this.$refs.uploader1.uploader.removeFile(file)
    }, 0);
    

全部代码

import uploader from 'vue-simple-uploader'
Vue.use(uploader)
 <uploader
  ref="uploader1"
   :options="options"
   :file-status-text="fileStatusText"
   :autoStart="false"
   @upload-start="onUploadStart"
   @file-added="onFileAdded"
   @file-progress="onFileProgress"
   @file-success="onFileSuccess"
   @file-error="onFileError"
   class="uploader-example">
     <uploader-unsupport></uploader-unsupport>
       <!-- <p>Drop files here to upload or</p> -->
       <el-button size="small" @click="beforeUploade">点击上传</el-button>
       <div>{{form.courseType == 2?'只能上传mp4,mov,avi格式':'上传音频格式的文件'}}</div>
       <div v-show="form.courseType == 2">
         <uploader-btn :attrs="attrs" v-show="false" id="shipin" ref="upload">选择{{form.courseType == 2?'视频':'音频'}}文件</uploader-btn>
       </div>
       <div v-show="form.courseType == 3">
         <uploader-btn :attrs="attrs1" v-show="false" id="yinpin" ref="upload1">选择{{form.courseType == 2?'视频':'音频'}}文件</uploader-btn>
       </div>
       <!-- <uploader-btn :directory="true">select folder</uploader-btn> -->
     <uploader-list v-show="!form.videoUrl"></uploader-list>
     <div v-show="form.videoUrl">{{form.videoUrl}}</div>
   </uploader>
import { upload } from '@/assets/mixins/upload.js'
mixins : [ upload ],

upload.js

import SparkMD5 from 'spark-md5';
import { getToken } from "@/utils/auth";
import { bigFile } from "@/api/course";
export const upload = {
  data(){
      return {
           // 文件上传参数
          uploaderInstance:undefined,
          options: {
            headers: { Authorization: "Bearer " + getToken() },
            // target: process.env.VUE_APP_BASE_API + "/file?type=1",
            target: process.env.VUE_APP_BASE_API + "/bigfile/upload",
            testChunks: false,
            chunkSize: 1024*1024*5,  //5MB
            simultaneousUploads: 3, //并发上传数
            maxChunkRetries: 2, //最大自动失败重试上传次数
            parseTimeRemaining: function (timeRemaining, parsedTimeRemaining) { //格式化时间
                return parsedTimeRemaining
                    .replace(/\syears?/, '年')
                    .replace(/\days?/, '天')
                    .replace(/\shours?/, '小时')
                    .replace(/\sminutes?/, '分钟')
                    .replace(/\sseconds?/, '秒')
            },
            testChunks: true,   //开启服务端分片校验
            // 服务器分片校验函数
            checkChunkUploadedByResponse: (chunk, message) => {
              let obj = JSON.parse(message);
              // console.log('sss',chunk,message,obj)
                if (obj.data.isExist=='true') {
                  console.log('aaa')
                    this.statusTextMap.success = '秒传文件,处理中····';
                    this.form.videoUrl = obj.data.url
                    return true;
                }
                // return (obj.uploaded || []).indexOf(chunk.offset + 1) >= 0
                return obj.data.uploaded >chunk.offset + 1
            },
          },
          statusTextMap: {
                success: '文件处理中···',
                error: '上传出错了',
                uploading: '上传中...',
                paused: '暂停',
                waiting: '等待中...',
                cmd5: '准备中...'
            },
          fileStatusText: (status, response) => {
              return this.statusTextMap[status];
          },
          attrs: { // 视频
            accept: 'video/*',
            // multiple: false,
            // multipleLimit:1
          },
          attrs1: { // 音频
            accept: 'audio/*',
            // multiple: false,
            // multipleLimit:1
          },
      }
  },
  methods: {
    onUploadStart(file){
      // this.uploaderInstance = this.$refs.uploader1.uploader
      // this.uploaderInstance.cancel()
    },
    beforeUploade(){
      // if(this.$refs.uploader1.files.length>1){
      //   console.log('文件列表1',this.$refs.uploader1.files,this.$refs.uploader1.fileList)
      //   // this.$refs.uploader1.files.shift()
      //   this.$refs.uploader1.uploader.cancel()
      //   // this.$refs.uploader1.uploader.pause(this.$refs.uploader1.files[0])
      //   // this.$refs.uploader1.uploader.removeFile(this.$refs.uploader1.files[0])
      //   // this.$refs.uploader1.uploader.fileRemoved(this.$refs.uploader1.files[0])
      // }
      // if(this.$refs.uploader1.fileList.length>1){
      //   console.log('文件列表2',this.$refs.uploader1.files,this.$refs.uploader1.fileList)
      //   this.$refs.uploader1.uploader.cancel()
      // }
      // document.querySelector('.uploader-btn>input').value=''
      // console.log('1111',this.$refs.uploader1.uploader.cancel)
      this.$refs.uploader1.uploader.cancel()
      this.form.videoUrl=''
      if(this.form.courseType == 2){
        document.querySelector('#shipin>input').nodeValue=''
        document.querySelector('#shipin>input').click()
      }else{
        document.querySelector('#shipin>input').nodeValue=''
        document.querySelector('#yinpin>input').click()
      }
    },
    onFileAdded(file) { // 文件上传前的校验
      console.log(file)
      if(this.form.courseType == 2&&file.fileType.indexOf('video')==-1){
        console.log('上传的不是视频')
        this.form.videoUrl=''
        this.$message.warning(this.form.courseType == 2?'请上传正确的视频类型':'请上传正确的音频类型')
        setTimeout(() => {
          this.$refs.uploader1.uploader.removeFile(file)
        }, 0);
        return
      }
      if(this.form.courseType == 3&&file.fileType.indexOf('audio')==-1){
        console.log('上传的不是音频')
        this.form.videoUrl=''
        this.$message.warning(this.form.courseType == 2?'请上传正确的视频类型':'请上传正确的音频类型')
        setTimeout(() => {
          this.$refs.uploader1.uploader.removeFile(file)
        }, 0);
        return
      }
      if(file.size/1024/1024>200){ // 文件不能大于200M
        this.form.videoUrl=''
        this.$message.warning('文件大小不能超过200M')
        setTimeout(() => {
          this.$refs.uploader1.uploader.removeFile(file)
        }, 0);
        return
      }
      this.computeMD5(file);
    },
    //计算MD5
    computeMD5(file) {
        let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
            chunkSize = 1024*1024*5,
            chunks = Math.ceil(file.size / chunkSize),
            currentChunk = 0,
            spark = new SparkMD5.ArrayBuffer(),
            fileReader = new FileReader();
            let time = new Date().getTime();
            file.cmd5 = true;
            fileReader.onload = (e) => {
              spark.append(e.target.result);   // Append array buffer
              currentChunk++;
        
              if (currentChunk < chunks) {
                  //console.log(`第${currentChunk}分片解析完成, 开始第${currentChunk +1} / ${chunks}分片解析`);
                  let percent = Math.floor(currentChunk / chunks * 100);
                  file.cmd5progress = percent;
                  loadNext();
              } else {
                  console.log('finished loading');
                  let md5 = spark.end();
                  console.log(`MD5计算完成:${file.name} \nMD5:${md5} \n分片:${chunks} 大小:${file.size} 用时:${new Date().getTime() - time} ms`);
                  spark.destroy(); //释放缓存
                  file.uniqueIdentifier = md5; //将文件md5赋值给文件唯一标识
                  file.cmd5 = false; //取消计算md5状态
                  file.resume(); //开始上传
              }
          };
          fileReader.onerror = () => {
              console.warn('oops, something went wrong.');
              file.cancel();
          };
        
          let loadNext = () => {
              let start = currentChunk * chunkSize,
                  end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
        
              fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));
          };
        
          loadNext();
    },
    // 文件进度的回调
    onFileProgress(rootFile, file, chunk) {
        console.log(`上传中 ${file.name},chunk:${chunk.startByte / 1024 / 1024} ~ ${chunk.endByte / 1024 / 1024}`)
    },
    onFileSuccess(rootFile, file, response, chunk) {
        let resp = JSON.parse(response);
        console.log('resp',resp)
        if(resp.data&&resp.data.isExist=='true'){
          return
        }
        //合并分片
        // if (resp.code === 0 && resp.merge === true) {
            bigFile({
                filename: file.name,
                identifier: file.uniqueIdentifier,
                // identifier: '9273dc4d57d39f382b53e02b3fbdcd5c',
                totalSize: file.size,
                totalChunks: chunk.offset + 1
            }).then((res)=>{
                console.log('res',res)
                if (res.code === 200) {
                    this.form.videoUrl = res.msg
                    console.log('上传成功')
                } else {
                    console.log(res.message);
                }
            })
            .catch(function(error){
                console.log(error);
            });
        // }
    },
    onFileError(rootFile, file, response, chunk) {
        console.log('Error:', response)
    },
  },
}
 类似资料: