前端实现断点续传文件

公司要求实现的功能,大概思路是将上传的文件通过jsZip压缩后,进行切片,留一下总切片,当前片,并把这些数据给后端,至于前端的校验,是由Md5完成的,验证文件唯一性,这样下次上传该文件的时候就会略过并更新已经上传过的切片,开始下一片的续传。

首先是创建一个上传按钮,绑定上传事件,我这边是需要放在表格里,并且需要是base64格式所以有个转换,具体看个人需求:

复制代码
  importModel() {

                this.fileIndex = 0
                const input = document.createElement('input');
                input.type = 'file';
                input.onchange = (event) => {
                let selectedFiles = this.fileFilter(event.target.files);
                if (selectedFiles.length > 0) {
                    const zip = new JSZip();

                    for (let i = 0; i < selectedFiles.length; i++) {
                        zip.file(selectedFiles[i].name, selectedFiles[i], { date: new Date(2023, 0, 1) });
                       
                    }
                    zip.generateAsync({ type: "base64" })
                        .then((content) => {
                            zip.generateAsync({ type: "uint8array" }).then(content1 => {
                                this.fileData = [
                                    { file: content, fileMd5: md5(content1), zipInfo: {}, type: '文件名 '+ '.zip', std: '50%', address: '删除', progressValue: 0 }
                                ];
                          })
                        });
                    this.compress = false;
                }
                else {
                    this.$message.error('请上传有效文件');
                }
            };
            input.click();
        },

接下来是上传的方法 (

复制代码
 uploadFiles() {
            if (this.fileIndex < this.fileData.length)
//下面这个接口是跟后端约定好的需要的参数,个人需求可以不用走,这边拿到返回的id再带给下一个方法,
                实际接口({
                    size://压缩后返回的大小,
                    fileName: 实际上传的文件名//
                })
                    .then(response => {
                        this.indexedDBHelper.get(this.fileData[this.fileIndex].fileMd5).then((d) => {
                            if (d)

                                this.fileData[this.fileIndex].zipInfo = d.data
                            else
                                this.fileData[this.fileIndex].zipInfo = {
                                    id: 后端带回来的id,看个人需求,
                                    fileSize:this.fileData[this.fileIndex].file.length,
                                    chunkSize: 4 * 1024 * 1024,
                                    chunkCount: Math.ceil(文件大小 / (4 * 1024 * 1024)),
                                    currentChunk: 0, //初始上传切片
                                }
                            this.uploadNextChunk()
                        })
                    });
            else
                console.log('全部上传完成')
        },

 
        ///上传文件切片
        uploadNextChunk() {
            let { currentChunk, chunkCount } = this.fileData[this.fileIndex].zipInfo
            if ((currentChunk) < chunkCount) {
                this.uploadChunk().then(response => {
                    this.showConnectingMessage = false;
                    if (response?.data) {
                        this.$set(this.fileData[this.fileIndex], 'progressValue', Math.round(((currentChunk + 1) / chunkCount) * 100));//更新进度条
                        this.fileData[this.fileIndex].zipInfo.currentChunk += 1
                        this.uploadNextChunk();

                        this.indexedDBHelper.set({ id: this.fileData[this.fileIndex].fileMd5, data: this.fileData[this.fileIndex].zipInfo })
                        //保存md5及信息到indexDB
                    }
                });

            } else {
                this.$set(this.fileData[this.fileIndex], 'progressValue', 100);
                this.indexedDBHelper.delete(this.fileData[this.fileIndex].fileMd5)
                //上传完成,清空md5
                this.fileIndex += 1

                this.uploadFiles()
                

            }

        },
        ///调用后端接口
        uploadChunk() {
            let start = (this.fileData[this.fileIndex].zipInfo.currentChunk) * this.fileData[this.fileIndex].zipInfo.chunkSize;
            let end = Math.min(this.fileData[this.fileIndex].zipInfo.fileSize, start + this.fileData[this.fileIndex].zipInfo.chunkSize);
             
            let chunkFile = this.fileData[this.fileIndex].file.slice(start, end);
            const uploadData = {
                id: this.fileData[this.fileIndex].zipInfo.id,
                fileBase64: 'Base64,' + chunkFile,
                fileName: this.fileData[this.fileIndex].zipInfo.fileName,
                size: chunkFile.length,
                chunks: this.fileData[this.fileIndex].zipInfo.chunkCount,
                chunk: this.fileData[this.fileIndex].zipInfo.currentChunk,
                md5: this.fileData[this.fileIndex].flieMd5,
            };
            return 后端接口(uploadData); //将数据发送给后端接口
        },

最后是删除方法,绑定在按钮上就可以

复制代码
deleteItem() {
            MessageBox.confirm('确定删除该文件吗?', '提示', {
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                type: 'warning'
            }).then(() => {
                后端接口(this.fileData[this.fileIndex].zipInfo.id)//将需要删除的id发送给后端
                    .then(response => {
                        const index = this.fileData.findIndex(item => item.id === this.fileData[this.fileIndex].zipInfo.id);
                        if (index !== -1) {
                            this.fileData.splice(index, 1);
                        }
                    })
                    .catch(error => {
                        console.error('删除文件时出错:', error);
                    });
            }).catch(() => {
            });
        },

虽然这个功能可以实现续传,整个流程也通了,但是有个问题就是无法承担太大的文件,如果需求是中小文件的话是可以用的,超大文件的话会崩。

相关推荐
m0_敲代码的彭于晏16811 小时前
Vercel 前端部署平台深度评测
前端
2301_322414280411 小时前
基于SpringBoot+Vue的休闲零食超市管理系统的设计与实现59004-计算机毕设 原创(免费领源码+部署教程+开发环境)
java·vue.js·spring boot·redis·mysql·决策树·推荐算法
怕浪猫12 小时前
外包和大厂的前端代码,差在凌晨三点
前端·面试·github
ACP广源盛1392462567312 小时前
Type-C 扩展坞方案选型笔记:DP1.4 转 HDMI2.0 桥接方案评估@ACP
笔记·硬件架构·hdmi·国产芯片·扩展坞
m0_敲代码的彭于晏16812 小时前
Vercel 前端部署与全栈开发实战指南
前端·状态模式
徐小夕13 小时前
花了3个月,我们做了一款 AI 版的“飞书文档”
前端·算法·github
贾伟康13 小时前
【化学实验室|17】HarmonyOS ArkTS 亮暗色与视觉令牌实战:集中颜色、间距和交互状态避免页面割裂
前端·移动开发·harmonyos·arkts·arkui
Csvn14 小时前
SSR/SSG/ISR(上):峡谷与渲染策略的时间预算
前端
Csvn14 小时前
SSR/SSG/ISR(下):可交互性、新鲜度与回源账
前端
酷炫码神14 小时前
Day 10|Pinia 状态管理:把散落在各组件的数据,收进一个全局仓库
android·开发语言·javascript