一.问题描述
在我们日常开发中,会遇到批量下载方面的问题;如上图所示,我们要批量下载图片,接下来我们就模拟实现这个功能,并将下载文件打包下载;
二.准备工作
2.1 JSZip
JSZip 是一个 javascript 库,用于创建、读取和编辑 .zip 文件,具有可爱而简单的 API。我们使用它来打包我们的下载文件;
下载完成以后,我们在dist里面可以找到相关js文件;
使用示例:
// 初始化一个zip打包对象
var zip = new JSZip();
// 创建一个被用来打包的名为Hello.txt的文件
zip.file("Hello.txt", "Hello World\n");
// 创建一个名为images的新的文件目录
var img = zip.folder("images");
// 这个images文件目录中创建一个base64数据为imgData的图像,图像名是smile.gif
img.file("smile.gif", imgData, {base64: true});
// 把打包内容异步转成blob二进制格式
zip.generateAsync({type:"blob"}).then(function(content) {
// content就是blob数据,这里以example.zip名称下载
// 使用了FileSaver.js
saveAs(content, "example.zip");
});
/*
最终下载的zip文件包含内容如下:
Hello.txt
images/
smile.gif
*/
在上面的示例代码中,用到了FileSaver.js ,接下来我们介绍一下.
2.2 FileSaver.js
File Saver.js是在客户端保存文件的解决方案,对于在客户端生成文件的Web应用程序来说是完美的,但是如果该文件来自服务器,我们建议您首先尝试使用Content-Disposition附件响应头,因为它具有更多的跨浏览器兼容性。
使用示例:
var blob = new Blob(["Hello, world!"], {type: "text/plain;charset=utf-8"});
FileSaver.saveAs(blob, "hello world.txt");
更多用法,请阅读File Saver.js
2.3 XMLHttpRequest
请阅读XMLHttpRequest - Web API 接口参考 | MDN
2.4 FileReader
请阅读FileReader - Web API 接口参考 | MDN
三.解决方案
<script>
//定义文件名称
var fileNames = ["小老头.jpg", "表情.png","pdf文件.pdf","excel文件.xlsx","故意错误文件.png"];
//文件下载路径
var urlsArr =["https://hx-pro.oss-cn-hangzhou.aliyuncs.com/68bb0ac4-af6e-41fa-9a91-462f128c82b5.jpg",
"https://hx-pro.oss-cn-hangzhou.aliyuncs.com/48ccd15f-c12f-4346-b761-048b6f564fce.png",
"https://hx-pro.oss-cn-hangzhou.aliyuncs.com/b1c6bf5e-b9e5-4381-bdb4-de440f674b12.pdf",
"https://hx-pro.oss-cn-hangzhou.aliyuncs.com/1f60a6de-28d4-4e65-b213-c27a50dcd813.xlsx",
"https://hx-pro.oss-cn-hangzhou.aliyuncs.com/404.png"] ;//大文件
//渲染好的base64数据
var base64Arr = new Array(urlsArr.length);
//当前下载数量
var alreadyDrawingNum = 0;
var zip = new JSZip();
//zip.file("readme.txt", "可在里面写相关信息");
//zip包里面的文件夹
var myFileZip = zip.folder("张三相关资料");
var saveFileName = "2019-12-30张三资料";
//开始渲染
getBase64ByAjax(urlsArr);
//请求获取对应文件的base64码
function getBase64ByAjax(urlsArr) {
for (let i = 0; i < urlsArr.length; i++) {
let xhr = new XMLHttpRequest();
//初始化一个请求
xhr.open('get', urlsArr[i], true);
xhr.diyData = {
"thisIndex": i
};
//一个用于定义响应类型的枚举值
xhr.responseType = 'blob';
//xhr.setRequestHeader("www11", "8899");
xhr.onload = function() {
let thisFileindex = this.diyData.thisIndex;
let thisFileStatus = this.status;
console.log(this.diyData.thisIndex);
if (thisFileStatus == 200) {
var blob = this.response;
var reader = new FileReader();
reader.readAsDataURL(blob); // 转换为base64,可以直接放入a标签href
reader.onload = function(e) {
//console.log(e.target.result);
console.log(thisFileindex + "-200-" + thisFileStatus);
base64Arr[thisFileindex] = ((e.target.result).split(',')[1]); //去头部
//通知渲染完成
alreadyDrawingNum = alreadyDrawingNum + 1;
}
} else {
console.log(thisFileindex + "-504-" + thisFileStatus);
fileNames[thisFileindex] = fileNames[thisFileindex] + "(!!此文件下载错误" + thisFileStatus + ").txt";
base64Arr[thisFileindex] = (""); //错误
//通知渲染完成
alreadyDrawingNum = alreadyDrawingNum + 1;
}
};
xhr.send();
}
}
//每个n时间看是否渲染完成,完成后保存
function isCompletedToBase64() {
setTimeout(function() {
console.log("****正在请求", alreadyDrawingNum);
if (urlsArr.length == alreadyDrawingNum) {
console.log("已完成渲染开始保存:", base64Arr);
saveFile();
$("#xiazai").text("下载完成");
} else {
$("#xiazai").append(".");
console.log("下载了" + base64Arr.length); //可在html里面设置进度条
isCompletedToBase64();
}
}, 100);
}
isCompletedToBase64();
$("#xiazai").text("正在下载");
function saveFile() {
for (let i = 0; i < base64Arr.length; i++) {
let fileName = fileNames[i]; //里面单独文件名
myFileZip.file(fileName, base64Arr[i], {
base64: true
});
}
zip.generateAsync({
type: "blob"
}).then(function(content) {
// see FileSaver.js
saveAs(content, "下载文件" + ".zip");
});
}
</script>
效果图:
四.小结
采用XMLHttpRequest ajax请求方式好处是:
1.能下载任意类型文件。
2.如果浏览器之前缓存过,可以从缓存里面直接加载图片。名字可以根据数组一一对应,网上方法一般不能对应名字。
3.自定义下载错误类型文本提示
五.附录
源码下载:ajax请求方式打包下载所有类型文件源码
参考文章