企业网盘之分片上传组件
效果展示
包含技术点
1、分片上传。
2、文件秒传。
3、文件夹上传
4、文件续传。
5、文件拖拽上传。
组件目录
实现分析
分片上传
通过h5 fileupload对象可以实现文件上传, mutiple属性可以支持文件多选。拿到文件对象后,调用完整的分片上传流程:计算md5-添加文件-获取鉴权信息-递归上传分片-上传完成。
如何切割文件分片?
方法介绍:blob.slice(); 属于blob对象的一个方法,而file对象是继承blob对象的,因此file对象也含有slice方法。
如何计算进度?
通过文件大小及分片计算算法,算出分片大小和分片数目以后,通过当前上传的分片数目除以总共分片数目得到进度信息。
如何计算上传速度?
每上传一个分片,记录分片上传请求的时间,通过分片的大小除以请求时间得到速度信息。
上传分片的代码:
// 上传分片 const uploadpart = (resolve, reject) => { let blob = file.slice((params.partnumber - 1) * chunksize, params.partnumber * chunksize); let begin = new date().gettime(); params['body'] = blob; s3.uploadpart(params, function (err, data) { if (err || item.status !== 'uploading') { reject(err || item.status); } else { item.percentage = math.round(params.partnumber * 100 / framenum); // 进度 let spend = (new date().gettime() - begin) / 1000; // 消耗时间 item.speed = math.round(blob.size / spend) * 1.3; // 速度 log_content.frameseq = params.partnumber; l_params.logcontent = json.stringify(log_content); // debugger; log(l_params).then(() => { if (params.partnumber < framenum) { params.partnumber += 1; uploadpart(resolve, reject); } else { item.status = 'success'; resolve(); } }).catch((err) => { reject(err); }); } }); };
文件秒传
秒传是将上传的文件与服务器中的文件进行比对,若云端存在相同文件,则将直接把文件秒速保存到你的网盘。调用“添加文件”接口,若服务端返回文件id,表明云端已存储相同文件,新的文件会存储为源文件的一份索引。
文件夹上传
chrome的私有属性webkitdiretory可以支持文件夹上传。分片上传流程需要增加递归创建文件夹:递归创建文件夹-计算md5-添加文件-获取鉴权信息-递归上传分片-上传完成。
判断文件为文件夹上传?
file.webkitrelativepath属性。
判断文件是否一次上传?
这里要处理的场景是,一个文件夹上传两次,第二次需要对文件夹重命名。如何判断一批文件是一次上传的,还是同名文件夹上传多次。可以通过上传框change的时候,构造文件对象增加时间戳属性,同一批文件的时间戳相同。
html:
<input ref="folder" @change='handlechange' name="folderinput" multiple="" webkitdirectory="" accept="*/*" type="file">
递归创建文件夹可参考node算法:
const mkdirs = (dirname, callback, errback) => { fs.stat(dirname, (err, stats) => { if (err) { mkdirs(path.dirname(dirname), () => { fs.mkdir(dirname, callback) }, errback) } else { if (stats.isdirectory()) { callback() } else { errback() } } }) }
文件续传
大文件在上传过程中进行中断网络或刷新浏览器等操作,重新登录可断点上传。后台记录文件上传的分片信息,当上传过程被终止以后,重新登录查询当前用户未上传成功的续传列表。存储那边会保留已上传的分片,断点上传从未上传的分片开始,可大大减少大文件上传终止需重新上传的时间。
文件拖拽上传
h5新特性可实现文件拖拽上传。其中,与拖拽文件相关的事件有dragover(文件拖拽在悬浮)
、dragleave(文件拖拽离开)
、drop(文件拖拽放下)。在事件对象中,一个
e.datatransfer
这样的属性,它是一个datatransfer
类型的数据,有如下的属性
属性 | 类型 | 说明 |
files | filelist | 拖拽的文件列表 |
items | datatransferitemlist | 拖拽的数据(有可能是字符串) |
types | array | 拖拽的数据类型 该属性在safari下比较混乱 |
完整的组件代码:
<template> <div class="uploadmask" style="position: fixed" :class="{ 'is-dragover': dragover }" v-show="dragover" @drop.prevent="ondrop" @dragover.prevent="ondragover" @dragleave.prevent="dragover = false" > <slot></slot> </div> </template> <script> export default { name: 'eluploaddrag', props: { disabled: boolean }, data() { return { dragover: false }; }, methods: { ondragover() { if (!this.disabled) { this.dragover = true; } }, /*eslint-disable*/ ondrop(e) { let _this = this; if (!this.disabled) { let event = e || window.event; this.dragover = false; let df = event.datatransfer; // 拖曳操作的过程中,我们可以用过datatransfer对象来传输数据,以便在拖曳操作结束的时候对数据进行其他的操作; let len = df.files.length; let dealfilecnt = 0; // 读取文件是个异步的过程,需要记录处理了多少个文件了 let files = []; function callback (files) { // 抛出文件数组 _this.$emit('file', files); } // 检测是否已经把所有的文件都遍历过了 function checkdropfinish () { if ( dealfilecnt === len - 1 ) { console.log('ie'); callback(files); // 所有的文件都遍历过了emit 出去 } dealfilecnt++; } if (df.items) { // 有datatransfer项目列表时 for (let i = 0; i < len; i++) { let entry = df.items[i].webkitgetasentry(); // 读取拖拽元素信息 if (entry.isfile && !entry.isdirectory) { // isdirectory是否是文件夹 files.push(df.files[i]); } } callback(files); } else { // ie浏览器 for (let i = 0; i < len; i++) { let dropfile = df.files[i]; if (dropfile.type) { files.push(dropfile); checkdropfinish() } else { try { var filereader = new filereader(); filereader.readasdataurl(dropfile.slice(0, 3)); filereader.addeventlistener('load', function (e) { console.log(e, 'load'); files.push(dropfile); checkdropfinish(); }, false); filereader.addeventlistener('error', function (e) { console.log(e, 'error,不可以上传文件夹'); checkdropfinish(); }, false); } catch (e) { console.log(e, 'catch error,不可以上传文件夹'); checkdropfinish(); } } } } } } }, mounted() { let app = document.getelementsbyclassname('app')[0]; app.ondragstart = function (e) { // 拖拽开始 e.preventdefault();//取消默认的链接元素和图片元素拖拽会触发拖拽上传 }; app.addeventlistener('dragover', (e) => { // 拖拽到另一个容器是促发 e.preventdefault(); this.ondragover(); }); } }; </script>
参照文章
上一篇: nginx系列2:搭建nginx环境
下一篇: PHP超级全局变量