前端下載文件成功後執行回調的方法

在項目中常常會有下載文件的需求,大多數時候我都是一個a標籤或者window.location.href = "";一行代碼搞定,可是最近有一個文件下載需求,由於下載的文件有點大,因此速度確實慢,基本以10m+才能下載下來,因此作了一個進度條,而後問題來了,怎麼能夠監聽文件是否下載完成,而後取消掉進度條。。。javascript

開始折騰了半天的jquery,整不成,決定用原生ajax寫,其中也本身整理了幾種方法,特此記錄哈html

第一種方法:原生ajax+FileReader

$("#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

第二種方法:window.open()

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

第三種方法:原生ajax+分頁查詢+遞歸下載

// 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

相關文章
相關標籤/搜索