前端大文件分片上传 进度条展示 上传暂停、开始、取消
(图片来源网络,侵删)
实现的效果:
1、多个大文件(支持10个G以上)分片上传
2、进度条展示进度
3、控制文件上传暂停和取消
实现关键点:
1、文件预处理(md5计算、请求和进度处理等)
(图片来源网络,侵删)
2、分片上传的流程(查询已上传分片、文件合并等)
3、文件的暂停、开始、取消
文件预处理
首先使用file类型的input框获取文件,对文件进行深拷贝,再清空input的value值(防止input的change事件不被触发)。
let files = e.target.files; let copiedFiles = [] for(let i = 0; i对文件进行处理,核心思想是为每个文件构造一个对象,封装该文件的md5信息(用于标识该文件)和进度、请求、取消标识(用于文件的暂停)等信息。
async bigFileChange(files) { // 新增的文件 let newFiles = []; // 筛选出检验合格的文件 let okFileIndexs = this.checkRules(files); for (let i = 0; i计算md5值采用的是SparkMD5,为了减少计算量,采用文件的第一块的md5作为整个文件的md5。
firstChunkMd5(file, chunkSize) { return new Promise((resolve, reject) => { const fileReader = new FileReader(); const spark = new SparkMD5.ArrayBuffer(); const chunk = file.slice(0, chunkSize); fileReader.onload = function (event) { spark.append(event.target.result); const md5 = spark.end(); resolve(md5); }; fileReader.onerror = function () { reject(new Error("File read error.")); }; fileReader.readAsArrayBuffer(chunk); }); }在界面上为每个文件创建进度条。
(图片来源网络,侵删){{ f.file.name }} {{ f.newSize }} { f.progress }}% --> {{ f.status }} 暂停 开始 取消分片上传
首先查询文件已经上传的分片数,如果全部上传了,进度立即更新为100%(秒传),如果没完全上传,则上传未上传的分片并实时更新进度,各分片上传完毕后请求合并,采用轮询检测合并进度。
this.checkFile(fileObj, chunks) .then(async (res) => { console.log(res); if (res.data.data.completed) { // 如果当前文件已经上传成功 则无需继续上传 fileObj.progress = 100; fileObj.status = "上传成功"; // 为成功上传的附件添加id if (res.data.data.attachmentId) { fileObj.attachmentId = res.data.data.attachmentId; } this.$forceUpdate(); // 强制重新渲染组件 this.$emit("fileUpdate"); } else { // 当前文件没有上传成功 // 获取已经上传的分片数组 let uploadedChunks = res.data.data.uploadChunks; // 获取当前的进度 let newProgress = parseInt( (uploadedChunks.length / chunks) * 100 ); fileObj.progress = newProgress; this.$forceUpdate(); // 强制重新渲染组件 // 文件均已上传完 但还未合并 if (res.data.data.canMerge || uploadedChunks.length == chunks) { this.mergeBigFile(fileObj) .then((res) => { fileObj.status = "合并中"; this.$forceUpdate(); // 强制重新渲染组件 // 先清除该文件上次的合并计时器 if (fileObj.mergeTimer) { clearInterval(fileObj.mergeTimer); } fileObj.mergeTimer = setInterval(() => { this.getMergeProcess(fileObj).then((res) => { if (res.data.data.completed) { fileObj.status = "上传成功"; // 为成功上传的附件添加id if (res.data.data.attachmentId) { fileObj.attachmentId = res.data.data.attachmentId; } this.$forceUpdate(); // 强制重新渲染组件 // 合并完成 fileObj.requests = []; fileObj.cancelTokens = []; clearInterval(fileObj.mergeTimer); this.$emit("fileUpdate"); } }); }, 2000); }) .catch((error) => { console.error("上传失败:", error); fileObj.status = "上传失败"; if (fileObj.mergeTimer) { clearInterval(fileObj.mergeTimer); } this.$forceUpdate(); }); } else { // 文件还没上传完 let currentChunk = 0; // 上传没有上传的部分 while (currentChunk { console.log(res); // 进行进度控制 let progress = parseInt( (res.data.data.uploadChunks.length / chunks) * 100 ); if (progress > fileObj.progress) { fileObj.progress = progress; this.$forceUpdate(); // 强制重新渲染组件 } // 进行文件的合并控制 if (res.data.data.canMerge) { // 文件可以合并了 this.mergeBigFile(fileObj) .then((res) => { fileObj.status = "合并中"; this.$forceUpdate(); // 强制重新渲染组件 // 先清除该文件上次的合并计时器 if (fileObj.mergeTimer) { clearInterval(fileObj.mergeTimer); } fileObj.mergeTimer = setInterval(() => { this.getMergeProcess(fileObj).then((res) => { if (res.data.data.completed) { fileObj.status = "上传成功"; // 为成功上传的附件添加id if (res.data.data.attachmentId) { fileObj.attachmentId = res.data.data.attachmentId; } this.$forceUpdate(); // 强制重新渲染组件 // 合并完成 fileObj.requests = []; fileObj.cancelTokens = []; clearInterval(fileObj.mergeTimer); this.$emit("fileUpdate"); } }); }, 2000); }) .catch((error) => { console.error("上传失败:", error); fileObj.status = "上传失败"; if (fileObj.mergeTimer) { clearInterval(fileObj.mergeTimer); } this.$forceUpdate(); }); } }) .catch((error) => { if (axios.isCancel(error)) { console.log("上传已暂停或取消"); } else { console.error("上传失败:", error); fileObj.status = "上传失败"; this.$forceUpdate(); } fileObj.requests = []; fileObj.cancelTokens = []; }); } } } }) .catch((error) => { console.error("Error:", error); fileObj.status = "上传失败"; this.$forceUpdate(); });上传暂停、开始、取消
暂停上传即根据取消标识将当前文件的所有请求进行取消。
pauseBigFile(fileObj) { fileObj.cancelTokens.forEach((item) => { item.cancel("上传暂停"); }); fileObj.isPaused = true; fileObj.status = "已暂停"; this.$forceUpdate(); // 强制重新渲染组件 }开始上传即对文件重新进行上传处理。
restartBigFile(fileObj) { fileObj.isPaused = false; fileObj.status = "上传中"; this.$forceUpdate(); // 强制重新渲染组件 fileObj.requests = []; fileObj.cancelTokens = []; this.uploadBigAttachment(fileObj); }取消上传是将文件所有请求取消并发送请求删除文件,这里不加赘述。
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。
还没有评论,来说两句吧...