JavaScript实现多⽂件下载⽅法解析
对于⽂件的下载,可以说是⼀个⼗分常见的话题,前端的很多项⽬中都会有这样的需求,⽐如 highChart 统计图的导出,在线图⽚编辑中的图⽚保存,在线代码编辑的代码导出等等。⽽很多时候,我们只给了⼀个链接,⽤户需要右键点击链接,然后选择“另存为”,这个过程虽说不⿇烦,但还是需要两步操作,倘若⽤户想保存页⾯中的多个链接⽂件,就得重复操作很多次,最常见的就是英语听⼒⽹站上的⾳频下载,⼿都要点⿇!
本⽂的⽬的是介绍如何利⽤ javascript 进⾏多⽂件的下载,也就是当⽤户点击某个链接或者按钮的时候,同时下载多个⽂件。这⾥的“同时”⽤的不是很准确,在现代浏览器中可以实现多⽂件的并⾏下载,⽽在⼀些⽼版本浏览器,如IE8-,此类的浏览器就只能进⾏单个⽂件的下载,但是我们可以让多个⽂件依次保存下来,算是串⾏下载吧~
若要要⽆视实现细节,可以直接跳到第三部分,或者戳:
代码封装:
DEMO:(HTTPS,第三个有bug,具体原因下⾯有说明)
(HTTP,测试正常)
⼀、⽂件类型介绍及其特点
1. ⼀般类型
平时⽐较常见的有 txt、png、jpg、zip、tar 等各种⽂件格式,这些⽂件格式中,⼀部分浏览器是会直接打开链接显⽰内容的,⽽另外⼀部分,浏览器不识别响应头,或者不能解析对应的格式,于是当做⽂件直接下载下来了。如:
<a href="barretlee/test.rar" rel="external nofollow" >file</a>
这句代码,若直接点开链接,浏览器将会直接下载该⽂件。
2. dataURL类型
dataURL 也是⼗分常见的类型,他可以作为 src 或者 url() 的参数送进去。⽐较常见的有如下⼏种:
⽂本: data:text/plain;这⾥是正⽂内容。
图⽚: data:image/jpg;base64,/
data:image/png;base64,/
base64 是⽤的⽐较⼴泛的⼀种数据格式。
Base64格式
data:[][;charset=][;base64],
Base64 在CSS中的使⽤:
.demoImg{ background-image: url("data:image/jpg;base64,/"); }
Base64 在HTML中的使⽤:
<img width="40" height="30" src="data:image/jpg;base64,/" />
3. Blob 流
Blob 对象表⽰不可变的、包含原始数据的类⽂件对象。具体的内容可以参阅。
他的使⽤也是特别的⽅便,如:
var aFileParts = ['<a id="a"><b id="b">hey!</b></a>'];
var oMyBlob = new Blob(aFileParts, {type : 'text/html'}); // the blob
Blob 接收两个参数,⼀个是数组类型的数据对象,他可以是 ArrayBuffer、ArrayBufferView、Blob、String 等诸多类型;第⼆个参数是 MINE 类型设置。⽽本⽂我们要⽤到的是 URLcreateObjectURL() 这个函数,他的作⽤是将⼀个 URL 所代表的内容转化成⼀个,产⽣的结果是⼀个⽂件对象或者 Blob 对象。
4. ⼆进制流
我们利⽤ File API 读取⽂件的时候,拿到的是数据的⼆进制流格式,这些类型可以直接被 ArrayBuffer 等接收,本⽂中没有⽤到,就不细说了。如何下载javascript
⼆、JavaScript 多⽂件下载
HTML5 中 a 标签多了⼀个属性——download,⽤户点击链接浏览器会打开并显⽰该链接的内容,若在链接中加了 download 属性,点击该链接不会打开这个⽂件,⽽是直接下载。虽说是⽐较好⽤,但低版本浏览器不兼容,这个在本节的 2 和 3 中将会讲到解决⽅案。
在这⾥,我们可以利⽤属性检测UA 来判断浏览器类型:
h5Down = ateElement("a").hasOwnProperty("download");
var h5Down = !/Trident|MSIE/.test(navigator.userAgent); // Trident 标识 IE11
1. a 标签 download 属性的使⽤
注:FF5.0 / Safari5.0 / Opera11.1 / IE9.0 不⽀持 download 属性
利⽤ download 属性可以直接下载单个⽂件,若想点击⼀次下载多个⽂件,就得稍加处理下了:
function downloadFile(fileName, content){
var aLink = ateElement("a"),
evt = ateEvent("HTMLEvents");
evt.initEvent("click");
aLink.download = fileName;
aLink.href = content;
aLink.dispatchEvent(evt);
}
download 属性的作⽤除了让浏览器忽略⽂件的 MIME 类型之外,还会把该属性的值作为⽂件名。你可以在 chrome 控制台运⾏这句程序:
downloadFile("barretlee.html", "./");
浏览器会提⽰是否保留(下载)该 html ⽂件。之前我们提到⽂件类型还可能是 dataURL 或者是 Blob 流,为了让程序也⽀持这些数据类型,稍微修改下上⾯的函数:
function downloadFile(fileName, content){
var aLink = ateElement('a');
, blob = new Blob([content])
, evt = ateEvent("HTMLEvents");
evt.initEvent("click");
aLink.download = fileName;
aLink.href = ateObjectURL(blob);
aLink.dispatchEvent(evt);
}
new Blob([content]),现将⽂件转换成⼀个 Blog 流,然后,使⽤ ateObjectURL() 将其转换成⼀个 DOMString。这样我们就⽀持 data64 和其他数据类型的 content 了~
2. window.open 之后 execCommand("SaveAs")
上⾯也提到了,尽管 download 属性是⼗分便利的 H5 利器,但低版本 IE 根本不赏脸,要说⽅法,IE 还是有很多⽅式去转换的,⽐如 ADOBE.STREAM 的 activeX 对象可以把⽂件转换成⽂件流,然后写⼊到⼀个要保存的⽂件中。这⾥要谈到的是略微⽅便⼀点的⽅式:先把内容写到⼀个新开的 window 对象中,然后利⽤ execCommand 执⾏保存命令,就相当于我们在页⾯上按下 Ctrl+S,这样页⾯内
的信息都会 down 下来。
// 将⽂件在⼀个 window 窗⼝中打开,并隐藏这个窗⼝。
var win = window.open("path/", "new Window", "width=0,height=0");
// 在 win 窗⼝中按下 ctrl+s 保存窗⼝内容
Command("SaveAs", true, "");
// 使⽤完了,关闭窗⼝
win.close();
这个过程⼗分明了,不过这⾥会存在⼀个问题,并不是程序的问题,⽽是浏览器的问题,如果我们⽤搜狗浏览器或者 360浏览器打开新窗⼝的话,他会新开⼀个标签页,⽽不是新开⼀个窗⼝,更可恶
的是部分浏览器拦截 window.open 的窗⼝(这个可以设置)。所以只好另觅他法了。
3. iframe 中操作
既然新开⼀个窗⼝那么⿇烦,我就在本窗⼝下完成⼯作~
function IEdownloadFile(fileName, contentOrPath){
var ifr = ateElement('iframe');
ifr.style.display = 'none';
ifr.src = contentOrPath;
document.body.appendChild(ifr);
// 保存页⾯ -> 保存⽂件
veChild(ifr);
}
⼀般的链接我们可以直接给 iframe 添加 src 属性,然后执⾏ saveAs 命令,倘若我们使⽤的是 data64 编码的⽂件,这个怎么办?
var isImg = contentOrPath.slice(0, 10) === "data:image";
// dataURL 的情况
isImg && tWindow.document.write("<img src='" +
contentOrPath + "' />");
这个也⽐较好处理,直接把⽂件写⼊到 iframe 中,然后在执⾏保存。
三、代码的封装与接⼝介绍
1. 代码的封装以及相关 DEMO
封装:
DEMO:(HTTPS,第三个有bug)
(HTTP,测试正常)
2. 接⼝的调⽤
提供了三个接⼝,⽀持单⽂件下载,多⽂件下载,多⽂件下载⾃定义命名。
1)单⽂件下载
Downer("./");
2)多⽂件下载
Downer(["./","./"]);
3)多⽂件下载⾃定义命名
Downer({
"1.txt":"./",
"2.jpg":"./file/test.jpg"
});
⽂件的 URL 如 ./file/test.jpg 都可以改成 base64 或者其他格式,如:
Downer({
//这是⼀个很长的 dataURI,我⽤负的text-indent隐藏了,可直接复制
"data64.jpg" : "data:image/jpg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAMCAgMCAgMD
AwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFB });
这⾥只做到了 chrome 兼容,IE 下懒得去看了,这个需求很少见!
四、服务器⽀持与后端实现
1. 后端实现
不使⽤前端,直接后端实现的原理,就是在响应头中加⼊⼀些特殊的标记,如前端发送这样的请求:
function download(path) {
var ifrm = ElementById(frame);
ifrm.src = "download.php?path="+path;
}
后端的响应为
<?php
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=".$_GET['path']);
readfile($_GET['path']);
>
告诉浏览器这是⼀个流⽂件,作为附件⽅式发送给你,请忽略 MINE type,直接保存。
2. 服务器配置
若后台是 apche 作为服务器,可以配置 htaccess ⽂件:
<filesmatch "\.(zip|rar)$"="">
Header set Content-Disposition attachment
</filesmatch>
意思是只要请求的是 zip 或者 rar 类型的⽂件,那么就添加⼀个 Content-Disposition:attachment 的响应头。这样就可以在 php 代码中省略⿇烦的操作。
五、⼩结
由于⾏⽂仓促,⽂中会有不少错误,对多⽂件下载有更好的提议,希望提出来共同分享!
实现多⽂件下载的⽅式肯定不⽌上⾯提到的⼏种,⽽且我这⾥封装的代码并没有在FF safari opera 中实现,因为他们还没兼容 download 属性,具体情况可以查看。建议在项⽬中把这样的事情交给后
端,⼏句代码可以搞定。
六、参考资料
AlloyTeam
Ahzaz's Blog
MDN
到此这篇关于JavaScript实现多⽂件下载⽅法解析的⽂章就介绍到这了,更多相关JavaScript多⽂件下载内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论