在項目中常常會有下載文件的需求,大多數時候我都是一個a標籤或者window.location.href = "";一行代碼搞定,可是最近有一個文件下載需求,由於下載的文件有點大,因此速度確實慢,基本以10m+才能下載下來,因此作了一個進度條,而後問題來了,怎麼能夠監聽文件是否下載完成,而後取消掉進度條。。。javascript
開始折騰了半天的jquery,整不成,決定用原生ajax寫,其中也本身整理了幾種方法,特此記錄哈html
$("#execlTo_btn").on("click",function(){ var itime = 0; $(btn).attr("disabled", "disabled"); $(btn).html(`正在下載<i style="color:blueviolet;">${itime}</i>`); var hurl = `yjToExel?yjjb=123`; var xhr = new XMLHttpRequest(); xhr.open('get', hurl, true); xhr.responseType = "blob"; xhr.onload = function() { if (this.status === 200) { var blob = this.response; var reader = new FileReader; reader.readAsDataURL(blob); reader.onload = function(e) { var headerName = xhr.getResponseHeader("Content-disposition"); var fileName = decodeURIComponent(headerName).substring(20); var a = document.createElement("a"); a.download = fileName; a.href = e.target.result; $("body").append(a); a.click(); $(a).remove(); clearTimeout(downloadTimer); $(btn).html("導出Execl"); $(btn).removeAttr("disabled"); } } } xhr.send(); var downloadTimer = setInterval(() => { $(btn).children("i").text(++itime); }, 1000); })
代碼解析:首先點擊下載按鈕確定先把按鈕給禁用了,等下載完成再運行點擊,這段代碼的關鍵在於獲取reponse的數據而後經過reader.readAsDataURL(blob);把字節流轉爲base64,而後再下載下來,這樣最大的缺點是數據量太大的時候,瀏覽器內存會爆,主要是字節流轉bese64後數據字符猛增致使的java
var itime = 0; $(btn).attr("disabled", "disabled"); $(btn).html(`正在下載<i style="color:blueviolet;">${itime}</i>`); loadExeclBtn(); var hurl = `yjToExel?yjjb=123`; let net = window.open(hurl); net.addEventListener("beforeunload", (e) => { clearTimeout(downloadTimer); $(btn).html("導出Execl"); $(btn).removeAttr("disabled"); }); var downloadTimer = setInterval(() => { $(btn).children("i").text(++itime); }, 1000);
代碼解析:首先一眼看去代碼是簡潔不少,並且進行大數據量的下載也是沒問題了,進行數據監聽也是很方便,可是這個方法最大的問題在於點擊下載後會新打開一個瀏覽器窗口,給我感受至關很差,故棄之jquery
// exel導出按鈕 //總條數 var datanum = 0; //請求地址數組 var getUrl = []; $("#execlTo_btn").on("click", function() { getUrl = []; var btn = this; $.get("getYjCount", { "yjjb": 123 }, function(data) { if (data && data < 50000) { if (data > 5000) { $("#queding_btn").show(); $("#guanbi_btn").show(); $("#fileListNum").text(data); $("#fileList_Modal").modal("show"); datanum = Math.ceil(data / 5000); let html = ""; for (var i = 0; i < datanum; i++) { if (data - i * 5000 > 5000) { html += `<li data-pagelist="${i}">${i*5000+1}條-${(i+1)*5000}條 <button data-ts="${i*5000+1}-${(i+1)*5000}條" id="to_execl_btn_${i}" class="btn btn-default execlTo_btn">未下載</button></li>`; } else { html += `<li data-pagelist="${i}">${i*5000+1}條-${data}條 <button data-ts="${i*5000+1}-${data}條" id="to_execl_btn_${i}" class="btn btn-default execlTo_btn">未下載</button></li>`; } getUrl.push(i); } $("#fileList_ul").html(html); } else { //第三個方法cyx var hurl = `yjToExel?nowpage=999&yjjb=123`; loadToExeclData(hurl, btn, "導出Execl", "導出數據.xlsx"); } } else { toastr.warning("最大數據下載量5萬!"); } }); }); //點擊肯定按鈕,只有在5000條以上的時候纔有這個事件 $("#queding_btn").on("click", function() { if (getUrl && getUrl.length > 0) { $("#queding_btn").hide(); $("#guanbi_btn").hide(); var hurl = `yjToExel?nowpage=0&yjjb=123`; loadToExeclData(hurl, document.getElementById("to_execl_btn_0"), "已下載", "預警導出數據(1-5000條).xlsx"); } }); function loadToExeclData(hurl, btn, btnName, fileName){ var itime = 0; $(btn).attr("disabled", "disabled"); $(btn).html(`正在下載<i style="color:blueviolet;">${itime}</i>`); //進度條的,不貼代碼了,本身能夠隨便寫 loadExeclBtn(btn); var xhr = new XMLHttpRequest(); xhr.open('get', hurl, true); xhr.responseType = "blob"; xhr.onload = function() { if (this.status === 200) { var res = this.response; const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); const a = document.createElement('a'); a.download = fileName; a.href = URL.createObjectURL(blob); a.click(); $(a).remove(); clearTimeout(downloadTimer); $(btn).html(btnName); $(btn).removeAttr("disabled"); if (getUrl && getUrl.length > 0) { getUrl.splice(0, 1); console.log(getUrl); if (getUrl.length > 0) { var loadBtn = document.getElementById(`to_execl_btn_${getUrl[0]}`); var loadUrl = `yjToExel?nowpage=${getUrl[0]}&yjjb=123`; console.log(loadUrl); loadToExeclData(loadUrl, loadBtn, "已下載", `預警導出數據(${loadBtn.dataset.ts}).xlsx`); }else{ $("#guanbi_btn").show(); } } } } xhr.send(); var downloadTimer = setInterval(() => { $(btn).children("i").text(++itime); }, 1000); }
代碼解析:這個方法是我最終使用的方法,咋一看,代碼量雖是猛然劇增,實際上是把原來的方法給剝離成了兩個方法,主要的思路是大於5000條數據就分次查詢而後遞歸下載,下載以後的數據直接使用字節流數據,能夠節省不少的內存空間,下載大數據量的速度也有了質的提高,後端的代碼也不貼了,就是一個分頁查詢,而後返回byte[]字節流,很簡單ajax