摘要:添加功能顯示待上傳文件列表支持移除待上傳文件使用顯示上傳進(jìn)度支持中斷上傳方法返回一個對象,用來表示上傳的進(jìn)度。監(jiān)聽數(shù)據(jù)傳輸進(jìn)行中通過監(jiān)聽這個事件,可獲得上傳進(jìn)度。
??上一篇《H5拖放+FormData接口+NodeJS,完整異步文件上傳(一)》,我們走通了拖放文件上傳的整個流程,但離實際使用場景還有差距。這篇,我們來添加幾個實際使用場景必要的功能,向?qū)嶋H使用再走一步。
添加功能顯示待上傳文件列表;
支持移除待上傳文件;
使用upload.onprogress顯示上傳進(jìn)度;
支持中斷上傳;
upload.progressXMLHttpRequest.upload方法返回一個 XMLHttpRequestUpload對象,用來表示上傳的進(jìn)度。這個對象是不透明的,但是作為一個XMLHttpRequestEventTarget,可以通過對其綁定事件來追蹤它的進(jìn)度。onprogres監(jiān)聽數(shù)據(jù)傳輸進(jìn)行中(通過監(jiān)聽這個事件,可獲得上傳進(jìn)度)。摘自MDN實現(xiàn)思路
??拖放文件到上傳區(qū)域時,將文件保存在一個文件數(shù)組中,添加并顯示文件相關(guān)信息和移除按鈕,點擊移除按鈕刪除文件數(shù)組中對應(yīng)的文件元素,點擊上傳按鈕,遍歷文件數(shù)組,開始上傳待上傳文件,此時點擊移除按鈕則中止文件上傳。
代碼//相關(guān)樣式 .drop-area{ margin:auto; width: 500px; height: 500px; border:1px pink dashed; } .close-btn{ cursor: pointer; } .close-btn:after{ float: right; content: "X"; color: red; } #fileList{ width: 95%; } .process-bar{ position: relative; margin: 0 10px 0 10px; width: 198px; height: 18px; display: none; text-align: center; line-height: 20px; color: #6dbfff; border-radius: 3px; border: 1px solid #1483d8; background: #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; width: 0; height: 100%; left: 0; top: 0; border-radius: 3px; background: #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{ content:"success"; position: absolute; margin: auto; left: 0; right: 0; z-index: 2; } .error .process-bar:after{ content: "error"; color: red; }
//Javascript代碼 let filesSet = []; //文件保存數(shù)組 let fileList = document.getElementById("fileList"); //獲取顯示文件列表DOM /** * 創(chuàng)建一個新的空白的文檔片段frag * 用于附加多個待上傳文件的DOM,可減小回流 * https://developer.mozilla.org/zh-CN/docs/Web/API/Document/createDocumentFragment */ let frag = document.createDocumentFragment(); let barDom = createProccessBar(); //創(chuàng)建進(jìn)度條DOM let submit = document.getElementById("submit") //獲取提交按鈕 /* 拖動到放置區(qū)域時 */ function dragover_hander (event) { /* 必須同時阻止dragover和drop的默認(rèn)事件 否則會響應(yīng)瀏覽器默認(rèn)行為 瀏覽器器能顯示的文件會直接顯示,例如html文件、圖片文件 瀏覽器器不能顯示的文件會出現(xiàn)文件下載彈窗 */ event.preventDefault(); } /*拖放完成事件*/ function drop_hander (event) { event.preventDefault(); //阻止默認(rèn)事件 var files = event.dataTransfer.files; //通過dataTransfer對象獲取文件對象數(shù)組 for(let file of files) { //遍歷文件對象數(shù)組 //創(chuàng)建文件信息顯示DOM,并保存在file對象的element屬性中,用于后續(xù)操作 file.element = createFileDom(file, filesSet.length) //復(fù)制進(jìn)度條DOM,并保存在file對象的processBar屬性中,用于后續(xù)操作 file.processBar = filesSet.length?barDom.cloneNode(true):barDom; //將進(jìn)度條添加至文件信息顯示DOM中 file.element.appendChild(file.processBar); //file文件對象添加到文件保存數(shù)組 filesSet.push(file); //創(chuàng)建文件信息顯示DOM添加至文檔片段frag frag.appendChild(file.element); } //將文件列表添加至顯示文件列表的div fileList.appendChild(frag) } /** * 創(chuàng)建文件信息顯示DOM * file 文件對象,用于獲取文件信息 * index 文件對象在數(shù)組中的索引,用于刪除 */ function createFileDom (file, index) { let p = document.createElement("p"); //file.name屬性可以獲得文件名稱 //有興趣的童鞋,可以使用for...in循環(huán)查看一下file對象的其它屬性值 let text = document.createTextNode(file.name); let span = document.createElement("span"); span.setAttribute("index", index); //索引添加至按鈕的index屬性 span.className = "close-btn"; p.appendChild(text); p.appendChild(span); return p; //返回文件信息顯示DOM } /** * 創(chuàng)建進(jìn)度條DOM, * 進(jìn)度條DOM結(jié)構(gòu)固定,可使用clone(true)進(jìn)行復(fù)制 * @return {[type]} [description] */ function createProccessBar() { let bar = document.createElement("span"); let rate = document.createElement("span"); let text = document.createElement("span"); bar.className = "process-bar"; rate.className = "process-rate"; text.className = "process-text"; text.innerText="0%"; bar.appendChild(text); bar.appendChild(rate); return bar; } //通過事件代理,監(jiān)聽移除或中止上傳 fileList.addEventListener("click", (evt)=>{ let index = evt.target.getAttribute("index"); //獲得index屬性值 if (index) { //存在index屬性值,表示點擊了刪除按鈕 if (filesSet[index].unloading && filesSet[index].req) { //文件已經(jīng)上傳中 filesSet[index].req.abort(); //中止上傳 filesSet[index].unloading = false; //將上傳中的狀態(tài)設(shè)置為false } else { //未開始上傳 filesSet[index].element.remove(); //移除DOM filesSet[index].element = null; //釋放對DOM的引用 filesSet[index].processBar = null;//釋放對DOM的引用 delete filesSet[index];//刪除文件數(shù)組中對應(yīng)的元素 } } }) submit.addEventListener("click",function(){// 為上傳按鈕綁定事件 //這里使用for...in循環(huán),正好可以避免對數(shù)組稀疏元素的遍歷 for(let key in filesSet){ //如果正在上傳中或已經(jīng)上傳完成,不再上傳 if (filesSet[key].unloading || filesSet[key].uploaded) continue; filesSet[key].unloading = true; //標(biāo)記開始上傳 //創(chuàng)建一個文件上傳的Promise,并設(shè)置成功及失敗的回調(diào) initUpload(filesSet[key]).then(file => { //上傳成功 file.element.className = "success"; //UI顯示成功信息 file.uploaded = true; //標(biāo)記上傳成功 }).catch((file, err) => { file.element.className = "error"; //UI顯示失敗信息 //取消開始上傳標(biāo)記,點擊上傳按鈕將嘗試再次上傳 filesSet[key].unloading = false; }) } }) /** * 返回一個文件上傳的Promise實例 * @param {[type]} file 要上傳的文件 */ function initUpload(file){ return new Promise((res, rej) => { let formData = new FormData();//聲明一個FormData實例 let req = new XMLHttpRequest();//創(chuàng)建XHR實例 let reta = file.processBar.querySelector(".process-rate");//獲得進(jìn)度條DOM let text = file.processBar.querySelector(".process-text");//獲得進(jìn)度文本DOM let pre;//保存上傳百分比 //監(jiān)聽數(shù)據(jù)傳輸進(jìn)行中 req.upload.onprogress =function(data){ pre = (data.loaded/data.total*100).toFixed(2);//計算百分比 reta.style.width = pre +"%";//修改進(jìn)度條 text.innerText = pre +"%" ;//修改進(jìn)度條文本 } //監(jiān)聽請求完成 req.onreadystatechange = function () { if (req.readyState !==4 ) return ; if (req.status === 200 ){ //完成,執(zhí)行成功回調(diào) res(file, req) } else { //失敗,執(zhí)行失敗回調(diào) rej(file, req) } } formData.append("file",file); //使用append方法添加文件到file鍵 req.open("POST", "/process_post"); //初始化請求 req.send(formData); //發(fā)送請求 file.req = req; //保存req對象,用于中止請求 //形如顯示上傳進(jìn)度 file.element.className = "uploading" }) }
??到這里代碼就結(jié)束了,完整代碼可以查看Github。因為是本地上傳,在測試的時候可以使用大一些的文件,或者限制一下上傳。
結(jié)束語??這些新的API,使得文件拖放上傳變得簡單起來。可惜低版本的IE并不支持,聽說低版本的IE可以使用Falsh來進(jìn)行文件上傳,具體是如何實現(xiàn)的,要不我們下篇再來探討一下。
??
??
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/52207.html
摘要:添加功能顯示待上傳文件列表支持移除待上傳文件使用顯示上傳進(jìn)度支持中斷上傳方法返回一個對象,用來表示上傳的進(jìn)度。監(jiān)聽數(shù)據(jù)傳輸進(jìn)行中通過監(jiān)聽這個事件,可獲得上傳進(jìn)度。 ??上一篇《H5拖放+FormData接口+NodeJS,完整異步文件上傳(一)》,我們走通了拖放文件上傳的整個流程,但離實際使用場景還有差距。這篇,我們來添加幾個實際使用場景必要的功能,向?qū)嶋H使用再走一步。 添加功能 顯...
摘要:前段時間面試過程中,頻繁遇到異步文件上傳的相關(guān)問題。所以,這會是一個拖放接口實現(xiàn)文件異步上傳的完整。監(jiān)聽放置元素的事件,通過對象可以獲得拖拽事件的狀態(tài)及數(shù)據(jù)。后端文件接收保存后端使用實現(xiàn)文件上傳。 ??前段時間面試過程中,頻繁遇到H5異步文件上傳的相關(guān)問題。還遇到過一個通過H5拖放功能實現(xiàn)文件異步上傳的問題,大概知道H5有新增拖拽功能可以接收文件,如何異步上傳文件就母雞了(攤手)。面試...
閱讀 3545·2021-09-06 15:13
閱讀 1533·2021-09-02 10:19
閱讀 2480·2019-08-30 15:52
閱讀 926·2019-08-29 15:25
閱讀 1572·2019-08-26 18:36
閱讀 501·2019-08-26 13:23
閱讀 1340·2019-08-26 10:46
閱讀 3506·2019-08-26 10:41