当前位置: 首页 > Web前端 > HTML5

H5拖拽式异步文件上传之二——上传进度监控

时间:2023-04-05 18:55:39 HTML5

在上一篇《H5拖放+FormData接口+NodeJS,完整异步文件上传(一)》中,我们已经走过了拖拽式文件上传的全过程,但是离实际使用场景。在这篇文章中,我们来添加几个实际使用场景所必需的功能,向实际使用又迈进了一步。增加显示待上传文件列表功能;支持删除要上传的文件;使用upload.onprogress显示上传进度;支持中断上传;upload.progressXMLHttpRequest.upload方法返回一个XMLHttpRequestUpload对象来指示上传进度。该对象是不透明的,但作为XMLHttpRequestEventTarget,可以通过将事件绑定到它来跟踪其进度。onprogres监听数据传输的进度(通过监听该事件可以获取上传进度)。摘自MDN实现思路?将文件拖放到上传区时,将文件保存在一个文件数组中,添加并显示文件相关信息和一个删除按钮,点击删除按钮删除文件数组中对应的文件元素,点击上传按钮,遍历File数组,开始上传要上传的文件,此时点击remove按钮停止文件上传。代码//相关样式.drop-area{margin:auto;宽度:500px;高度:500px;border:1pxpinkdashed;}.close-btn{cursor:pointer;}.close-btn:after{float:right;内容:'X';颜色:红色;}#fileList{宽度:95%;}.process-bar{位置:相对;边距:010px010px;宽度:198px;高度:18px;显示:无;文本对齐:居中;行高:20px;颜色:#6dbfff;边界半径:3px;边框:1px实心#1483d8;背景:#fff;}.success.process-bar,.uploading.process-bar{display:inline-block;}.process-bar.process-text{position:relative;z-index:1;}.process-bar.process-rate{position:absolute;宽度:0;高度:100%;左:0;顶部:0;边界半径:3px;背景:#1483d8;}.file-list.success.process-text,.file-list.success.close-btn:after,.file-list.error.process-text,.file-list.error.close-btn:after{display:none;}.success.process-bar:after,.error.process-bar:after{内容:'成功';位置:绝对;保证金:自动;左:0;右:0;z-index:2;}.??error.process-bar:after{内容:“错误”;color:red;

上传//Javascript代码letfilesSet=[];//文件存储数组letfileList=document.getElementById('fileList');//获取显示文件列表DOM/***新建一个空白文档片段frag*用于附加多个待上传文件的DOM,可以减少reflow*https://developer.mozilla.org/zh-CN/docs/Web/API/Document/createDocumentFragment*/letfrag=document.createDocumentFragment();letbarDom=createProccessBar();//创建一个进度条DOMletsubmit=document.getElementById("submit")//获取提交按钮/*拖到拖放区时*/functiondragover_hander(event){/*dragover和drop的默认事件必须是同时阻止或它会响应浏览器的默认行为是浏览器能显示的文件会直接显示,比如html文件,图片文件,浏览器不能显示的文件,会出现文件下载弹窗*/event.preventDefault();}/*拖放完成事件*/functiondrop_hander(event){event.preventDefault();//防止默认事件varfiles=event.dataTransfer.files;//通过dataTransfer对象获取文件对象数组for(letfileoffiles){//遍历文件对象数组//创建文件信息显示DOM,保存在文件对象的element属性中,用于后续操作file.element=createFileDom(file,filesSet.length)//复制进度条DOM,保存在file对象的processBar属性中,用于后续操作file.processBar=filesSet.length?barDom.cloneNode(true):barDom;//添加进度条到文件信息显示DOMfile.element.appendChild(file.processBar);//file文件对象加入文件保存数组filesSet.push(file);//创建文件信息显示DOM添加到文档片段中fragfrag.appendChild(file.element);}//将文件列表添加到divfileList.appendChild(frag)}/***创建文件信息显示DOM*文件文件对象,用于获取文件信息*index文件对象在数组中的索引,用于删除*/函数createFileDom(文件,索引){让p=文档。创建元素('p');//file.name属性可以获取文件名//有兴趣的童鞋,可以使用for...in循环检查文件对象的其他属性值lettext=document.createTextNode(file.name);让span=document.createElement("span");span.setAttribute('索引',索引);//给按钮的index属性添加索引span.className='close-btn';p.appendChild(文本);p.appendChild(跨度);返回p;//返回文件信息显示DOM}/***创建进度条DOM,*进度条的DOM结构是固定的,可以使用clone(true)复制*@return{[type]}[description]*/functioncreateProccessBar(){letbar=document.createElement("span");让rate=document.createElement("span");让text=document.createElement("span");bar.className="进程栏";rate.className="process-rate";text.className="进程文本";text.innerText="0%";bar.appendChild(文本);bar.appendChild(率);返回栏;}//通过事件代理,监听移除或停止上传fileList.addEventListener('click',(evt)=>{letindex=evt.target.getAttribute('index');//获取index属性值if(index){//有一个index属性值,表示点击了删除按钮if(filesSet[index].unloading&&filesSet[index].req){//文件已经上传filesSet[index].req.abort();//中止上传文件Set[index].unloading=false;//设置上传状态为false}else{//未开始上传文件Set[index].element.remove();//移除DOM文件Set[index].element=null;//释放对DOM文件的引用Set[index].processBar=null;//释放对DOM的引用deletefilesSet[index];//删除文件数组中对应的元素}}})submit.addEventListener('click',function(){//为上传按钮绑定事件//这里使用for...in循环正好可以避免遍历数组的稀疏元素for(letkeyinfilesSet){//如果正在上传或者已经上传已上传,如果(filesSet[key].unloading||filesSet[key].uploaded)continue;filesSet[key].unloading=true;//标记开始上传//创建文件上传的Promise,并且设置成功和失败回调initUpload(filesSet[key]).then(file=>{//上传成功file.element.className="success";//UI显示成功信息file.uploaded=true;//标记上传成功}).catch((file,err)=>{file.element.className="错误";//UI显示失败信息//取消开始上传标志,点击上传按钮尝试上传文件Set[key].unloading=false;})}})/***返回文件上传的Promise实例*@param{[type]}file要上传的文件*/functioninitUpload(file){returnnewPromise((res,rej)=>{letformData=newFormData();//声明一个FormData实例letreq=newXMLHttpRequest();//创建一个XHR实例letreta=file.processBar.querySelector('.process-rate');//获取进度barDOMlettext=file.processBar.querySelector('.process-text');//获取进度TextDOMletpre;//保存上传百分比//监控数据传输进行中req.upload.onprogress=function(data){pre=(data.loaded/data.total*100).toFixed(2);//计算百分比reta.style.width=pre+'%';//修改进度条text.innerText=pre+'%';//修改进度条文字}//监听请求完成req.onreadystatechange=function(){if(req.readyState!==4)return;if(req.status===200){//完成,执行成功回调res(file,req)}else{//失败,执行失败回调rej(file,req)}}formData.append('file',file);//使用append方法向文件key添加文件req.open('POST','/process_post');//初始化请求req.send(formData);//发送请求file.req=req;//保存req对象,用于中止请求//Shapelike显示上传进度file.element.className="uploading"})}代码到此结束。你可以在Github上查看完整代码。因为是本地上传,所以测试的时候可以使用更大的文件,或者限制上传。结论这些新的API使拖放文件上传变得容易。可惜低版本IE不支持。听说低版本的IE可以用Falsh上传文件。它是如何实施的?让我们在下一篇文章中讨论它。