前端下载文件成功后执行回调的方法

原创
2018/08/15 11:34
阅读数 1.4W

在项目中经常会有下载文件的需求,大多数时候我都是一个a标签或者window.location.href = "";一行代码搞定,但是最近有一个文件下载需求,因为下载的文件有点大,所以速度确实慢,基本以10m+才能下载下来,所以做了一个进度条,然后问题来了,怎么可以监听文件是否下载完成,然后取消掉进度条。。。

开始折腾了半天的jquery,整不成,决定用原生ajax写,其中也自己整理了几种方法,特此记录哈

第一种方法:原生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后数据字符猛增导致的

第二种方法: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);

代码解析:首先一眼看去代码是简洁很多,而且进行大数据量的下载也是没问题了,进行数据监听也是很方便,但是这个方法最大的问题在于点击下载后会新打开一个浏览器窗口,给我感觉相当不好,故弃之

第三种方法:原生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[]字节流,很简单

 

 

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部