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

前言

教育项目视频上传、大文件频频上传失败、进度到100%后,服务端响应时间过长,影响观感。
继而采取分片上传方式,轮子有:
Web Uploader:http://fex.baidu.com/webuploader/
vue-simple-uploader:https://github.com/simple-uploader/vue-uploader
我们先看下可以直接npm导入的 vue-simple-uploader

简介

vue-simple-uploader就是一个基于 simple-uploader.js 和Vue结合做的一个上传组件,
自带 UI,可覆盖、自定义。它支持文件、多文件、文件夹上传;支持拖拽文件、
文件夹上传;可暂停、继续上传;支持秒传;上传队列管理,支持最大并发上传;
分片上传;支持进度、预估剩余时间、出错自动重试、重传等操作。
  1. 安装

    npm install vue-simple-uploader --save
    
  2. main全局导入

	import uploader from 'vue-simple-uploader'
    import App from './App.vue'
   	Vue.use(uploader)

需求和使用

  1. 项目需求
1、视频文件
2、一次只能上传一个,再次上传的视频文件会替换第一次上传
3、进度控制到99%
4、其余自定义

2.template

<uploader
   ref="uploader1"
   :options="options"
   :file-status-text="fileStatusText"
   @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>只能上传mp4,mov,avi格式</div>
       <uploader-btn :attrs="attrs" v-show="false" ref="upload">选择视频文件</uploader-btn>
       <!-- <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>
分析解释:
1、 options:uploader属性配置
fileStatusText:上传结果信息提示
@upload-start="onUploadStart" // 上传开始监听
@file-added="onFileAdded" // 文件上传到服务器前操作,可用校验等
@file-progress="onFileProgress" // onFileProgress上传进度回调
@file-success="onFileSuccess" // 所有分片上传完毕执行
@file-error="onFileError" // 上传错误监听

2、<uploader-btn :attrs="attrs" v-show="false" ref="upload">选择视频文件</uploader-btn>
attrs:{}默认添加属性到input
3、思路分析
采用el-button 按钮的beforeUploade调取页面隐藏uploader-btn标签上传,
是为了点击上传按钮前多一步操作,用于重置已经存在的文件,保证始终只有一个文件
  1. data中的参数
  // 文件上传参数
     uploaderInstance:undefined, // 用于保存ref即uploader组件
     options: {
       headers: { Authorization: "Bearer " + getToken() }, // 接口必须
       target: process.env.VUE_APP_BASE_API + "/file?type=1", // 接口url地址
       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);
           if (obj.isExist) {
               this.statusTextMap.success = '秒传文件';
               return true;
           }
           return (obj.uploaded || []).indexOf(chunk.offset + 1) >= 0
       },
     },
     statusTextMap: {
           success: '上传成功',
           error: '上传出错了',
           uploading: '上传中...',
           paused: '暂停',
           waiting: '等待中...',
           cmd5: '计算md5...'
       },
     fileStatusText: (status, response) => {
         return this.statusTextMap[status];
     },
     attrs: {
       accept: 'video/*',
       // multiple: false, 
     },

注意事项:

attrs: {
       accept: 'video/*',
       // multiple: false, 
     },
     在这里设置禁止input多选无效,我们后面优化会修改源码进行控制以及进度条只让它显示99%
  1. methods
 onUploadStart(file){
     // 上传开始执行
   },
   beforeUploade(){ 
   	// .cancel() 取消上传且从文件列表中移除
     this.$refs.uploader1.uploader.cancel()
     this.form.videoUrl='' //保存最终上传成功的url地址 
     document.querySelector('.uploader-btn>input').click()
   },
   onFileAdded(file) { // 文件上传前的校验
       // 计算MD5   下一章我会讲到
       // this.computeMD5(file);
   },
   //计算MD5
   computeMD5(file) {
       let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
           chunkSize = 2097152,
           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)
       this.form.videoUrl = resp.data.url
       //合并分片 所有上传结束通知后端进行合并分片
       // if (resp.code === 0 && resp.merge === true) {
       //     axios.post('http://localhost:9999/up.php?action=merge', {
       //         filename: file.name,
       //         identifier: file.uniqueIdentifier,
       //         totalSize: file.size,
       //         totalChunks: chunk.offset + 1
       //     }).then(function(res){
       //         if (res.code === 0) {
       //             console.log('上传成功')
       //         } else {
       //             console.log(res.message);
       //         }
       //     })
       //     .catch(function(error){
       //         console.log(error);
       //     });
       // }
   },
   onFileError(rootFile, file, response, chunk) {
       console.log('Error:', response)
   },
  1. 修改vue-simple-uploader:进度只能到99%,去掉input的multiple
   修改node_modules下面的vue-simple-uploader中dist中的vue-uploader.js

在这里插入图片描述

页面搜索:Ctrl F 搜索100找到修改为99,进度控制
progressStyle:function(){var e=Math.floor(99*this.progress)
搜索multiple进行删除,禁止多传
npm run dev 重启项目即可
  1. 文章参考
来源于helloweba.net,保留原文链接:https://www.helloweba.net/php/634.html
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
你可以使用 vue-simple-uploader 插件实现 Vue3 中的大文件上传功能。下面是一个简单的示例代码: 首先,安装 vue-simple-uploader 插件: ```bash npm install vue-simple-uploader --save ``` 然后,在需要使用上传功能的组件中引入插件并配置: ```javascript import Vue from 'vue'; import VueSimpleUploader from 'vue-simple-uploader'; Vue.use(VueSimpleUploader, { chunkSize: 1024 * 1024, // 设置分片大小,默认为1MB concurrentUploads: 3, // 设置并发上传数,默认为3 retryCount: 3, // 设置上传重试次数,默认为0 }); export default { // ... } ``` 接下来,你可以在组件中使用 `<vue-simple-uploader>` 标签来实现文件上传: ```html <template> <div> <vue-simple-uploader ref="uploader" :url="uploadUrl" @file-added="handleFileAdded" @file-progress="handleFileProgress" @file-success="handleFileSuccess" @file-error="handleFileError" @upload-started="handleUploadStarted" @upload-completed="handleUploadCompleted" > <button @click="startUpload">开始上传</button> </vue-simple-uploader> </div> </template> <script> export default { data() { return { uploadUrl: 'http://your-upload-url', // 设置上传接口地址 }; }, methods: { handleFileAdded(file) { console.log('文件添加成功:', file); }, handleFileProgress(file, progress) { console.log('上传进度:', progress); }, handleFileSuccess(file, response) { console.log('上传成功:', response); }, handleFileError(file, error) { console.log('上传失败:', error); }, handleUploadStarted() { console.log('上传开始'); }, handleUploadCompleted() { console.log('上传完成'); }, startUpload() { this.$refs.uploader.upload(); // 调用上传方法 }, }, }; </script> ``` 以上代码是一个简单的大文件上传示例,你可以根据需要自定义处理文件上传的各个事件。参考文档和示例代码以便更好地理解和使用 vue-simple-uploader 插件:https://github.com/simple-uploader/vue-simple-uploader

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值