vue中使用webuploader做断点续传实现文件上传功能
作者:火海柯神
之前做的一个项目中,由于经常上传几百兆的压缩包,导致经常上传失败,所以就找了webuploader插件做了断点续传,断点续传除了需要前端分片,也需要后台去支持,所以做的时候做好对接协调,所以本文就给大家详细的介绍一下vue中如何使用webuploader做断点续传
1、下载webuploader
npm i webuploader
2、导入并挂载到原型上
在main.js中导入,全局注册,挂载到原型上方便调用
import WebUploader from 'webuploader'; Vue.prototype.WebUploader = WebUploader; import "webuploader/dist/webuploader.css";
挂载到原型上之后就可以通过 this.WebUploader 去调用 之所以还要导入 webuploader.css 文件,是因为这样在初始化时,才会有正常的按钮样式,样式不符合需求也可以通过自己写样式去覆盖掉,否则初始化之后就只是一个type = file的input框,不方便调整样式
3、md5校验
上传一半取消了,再次上传,怎么接着上传?就需要进行md5校验,后台才知道原来这个文件之前已经上传过了,不需要重头上传
另外,md5的校验必须要写在初始化之前
// 断点续传的按钮初始化之前调用 webUploadBeforeInit(chunkSize) { this.WebUploader.Uploader.register({ "before-send-file": "beforeSendFile", "before-send": "beforeSend", }, { // 时间点1:所有分块进行上传之前调用此函数 beforeSendFile: (file) => { let deferred = this.WebUploader.Deferred(); let Uploader = new this.WebUploader.Uploader() Uploader.md5File(file, 0, chunkSize).progress(percentage => { debugger; console.log("校验MD5中...") }).then(md5 => { file.md5 = md5; file.uid = this.WebUploader.Base.guid(); // 进行md5判断 this.axios({ url: this.commonUrl + "/FileUploadController/checkFile", method: "get", params: { fileName: file.name, md5: file.md5, }, }).then(res => { let status = res.code; deferred.resolve(); switch (status) { case 0: // 表示上传成功或者已经上传过了 // 忽略上传过程,直接标识上传成功; Uploader.skipFile(file); file.pass = true; break; case 16: // 部分已经上传到服务器了,但是差几个模块。 file.missChunks = res.data; break; default: break; // 另外我这里,12表示未上传,1表示添加失败,这里不需要做其他处理 } }).catch((err) => { deferred.reject(); }); }); return deferred.promise(); }, beforeSend: (block) => { let deferred = this.WebUploader.Deferred(); // 当前未上传分块 let missChunks = block.file.missChunks; // 当前分块 let blockChunk = block.chunk; if (missChunks !== null && missChunks !== undefined &&missChunks !== "") { let flag = true; for (let i = 0; i < missChunks.length; i++) { if (blockChunk === parseInt(missChunks[i])) { // 存在还未上传的分块 flag = false; break; } } if (flag) { deferred.reject(); } else { deferred.resolve(); } } else { deferred.resolve(); } return deferred.promise(); }, } ); },
4、封装初始化方法
有关webuploader配置项、事件等,可详细参考 WebUploader API文档 - Web Uploader (baidu.com)
webUploadResume(opt, evt){ if(!(opt && this.isObj(opt))) return console.error("请传类型为对象的配置项opt,pick必传") // md5校验在初始化之前 this.webUploadBeforeInit(opt.chunkSize || 10485760) // 初始化 let uploader = this.WebUploader.create({ // 文件上传调的便是此接口 server: this.commonUrl + "/FileUploadController/breakpointUpload", method: opt.method || "post", // 这个外部是必传,要选一个dom初始化,无法给默认值。 // 可以直接给ID,如"#abc",可以是对象,如 // { // id:"#abc", // 虽然名是id,但实际也可以是类名或标签名 // innerHTML:"按钮文字,可不传", // multiple:true/false 是否多选, // } pick: opt.pick, // 制定对那个dom进行初始化 // 指定上传的哪些类型的文件 // { // title:"文字描述" , // extensions:"允许的文件后缀,不带点,多个用逗号分割,比如gif,jpg,jpeg,bmp,png", // mimeTypes: "多个用逗号分割,如image/*或者.gif,.jpg,.bmp" // } accept: opt.accept || null, resize: opt.resize || false, // 不压缩img auto: opt.auto || true, // 是否开启自动上传 threads: opt.threads || 1, // 上传并发数。允许同时最大上传进程数 chunked: opt.chunked || true, // 是否分片上传 chunkSize: opt.chunkSize || 10485760, // 分片大小,以B为单位,这里是10M = 10 * 1024 * 1024 B chunkRetry: opt.chunkRetry || 2, // 如果某个分片由于网络问题出错,允许自动重传多少次 duplicate: opt.duplicate || true, // 重复上传,为了解决上传一个后若上传失败,需再次上传,会无反应 formData: opt.formData || {}, // 文件上传请求的额外参数 fileNumLimit: opt.fileNumLimit || undefined, // 验证文件总数量, 超出则不允许加入队列 fileSizeLimit: opt.fileSizeLimit || undefined, // 验证文件总大小是否超出限制, 超出则不允许加入队列 fileSingleSizeLimit: opt.fileSingleSizeLimit || undefined, // 验证单个文件大小是否超出限制, 超出则不允许加入队列 // 主要看接口是否需要token,不需要的话,下方headers可以去掉 headers:{ token: sessionStorage.tkn } }) // 绑定事件 // beforeFileQueued, 当文件被加入队列之前触发 // fileQueued, 当文件被加入队列以后触发 // filesQueued, 当一批文件添加进队列以后触发 // startUpload, 当开始上传流程时触发 // stopUpload, 当开始上传流程暂停时触发 // uploadBeforeSend, 当某个文件的分块在发送前触发,主要用来询问是否要添加附带参数 // uploadProgress, 上传过程中触发,携带上传进度 // uploadSuccess, 当文件上传成功时触发 // uploadError, 当文件上传出错时触发 // uploadComplete, 不管成功或者失败,文件上传完成时触发 // uploadFinished, 当所有文件上传结束时触发 // error, 当validate不通过时,会以派送错误事件的形式通知调用者 // addFail, 当add接口失败后执行(非webuploader插件所带,为自定义) if(evt && this.isObj(evt)){ for(let k in evt){ if(k == "uploadError" || k == "uploadSuccess"){ uploader.on(k, (file, resp) => { this.axios({ url:this.commonUrl + "/FileUploadController/add", method:"post", data:{ fileName: file.name, // 文件名 suffix: file.ext, // 文件后缀 uploadStatus: k == "uploadSuccess"?1:0, }, }).then(res => { evt[k](res,file,resp) }).catch(err => { evt.addFail && evt.addFail(file, resp) }) }) }else if(k != "addFail"){ uploader.on(k, evt[k]) } } }else{ console.error("断点续传事件evt未传或传的类型错误") } },
5、调用封装的初始化方法进行初始化
<template> <div id="addFail"></div> </template> <script> data(){ return {} }, mounted(){ this.webUploaderInit() }, methods:{ webUploaderInit(){ // 封装的方法也是挂载到原型上的,方便调用 this.$tu.webUploadResume({ pick: "#addFail", accept: { title: "rar,zip", extensions: "rar,zip", mimeTypes: ".rar,.zip", }, fileSizeLimit: 1073741824, // 总大小不超过1G },{ beforeFileQueued: this.beforeFileQueued, uploadProgress: this.uploadProgress, uploadSuccess: this.uploadSuccess, uploadError: this.uploadError, error: this.error, addFail: this.addFail, }) }, beforeFileQueued(file){ // 注意区分beforeFileQueued和uploadBeforeSend // beforeFileQueued是选择文件时,即将加入要上传的文件队列但还没加入时 // uploadBeforeSend是即将开始调用上传接口,但还没调用 }, uploadProgress(file, percentage){ // percentag,即上传进度 // 一般用法 percentag * 100 + "%" 或者 percentag * width + "px" }, // 注意我这里uploadSuccess和uploadError跟其他事件注册不太一样,所以接受参数与api文档并不完全一致 uploadSuccess(res,file,resp){……}, uploadError(err,file,resp){……}, error(type){ // 当 type == "Q_EXCEED_SIZE_LIMIT",就意味着选中的文件总大小超过了设置的fileSizeLimit // 当 type == "Q_EXCEED_NUM_LIMIT",就意味着选中的文件数量超过了设置的fileNumLimit // 当 type == "Q_TYPE_DENIED",就意味着选中的文件不符合accept中设置的文件格式 // 另外,如果设置了 fileSingleSizeLimit,即使不符合也不会进入到这里 // 因为如果选择了A文件超过,B文件未超,那么会将A文件自动过滤掉,只将B加入到文件队列 }, // 无论uploadSuccess还是uploadError都会调用add接口,那么add也可能会因为某些情况调用失败 // 针对此情况,增加了自定义addFail方法,当add接口调用失败时会执行下面方法 addFail(file, resp){……}, }, </script>
初始化成功之后,页面便能看到这样一个按钮
点击即可上传。若样式不符合需求,可以F12找到相关类名,进行样式覆盖
外,在覆盖样式时,注意:
- 你看到的“断点续传”的按钮样式是,类名为webuploader-pick的div
- 而你点击时,之所以能打开选择文件的弹窗,并非是点击了这个div,实际是点击了下面的lable标签
- 所以,覆写样式时,注意label标签要和div的位置保持一致,否则就会出现点击但没有任何反应,因为只是点了div,并没有点击到label
以上就是vue中使用webuploader做断点续传的方法详解的详细内容,更多关于vue webuploader断点续传的资料请关注脚本之家其它相关文章!