最近有一个单独和批量下载 pdf 的文件的需求。单独下载首先想到的是用 a 标签 download 属性直接下载。实践中发现,浏览器会默认打开pdf文件,而不是直接下载。批量下载须要压缩,这一步也须要在前端实现。前端
这里记录下个人实现方式。适用于绝大部分文件。ajax
这里用到了两个 npm 包:npm
jszip
用于压缩。file-saver
用于在前端保存文件。promise
npm install file-saver jszip --save
安装好以后,先实现单独下载。浏览器
单独下载 pdf,只用 file-saver 就能够了。缓存
import { saveAs } from 'file-saver'; function save() { saveAs(blob, filename); }
saveAs 方法有两个参数,第二个参数是下载的文件名,第一个参数就比较难获取了,是一个 Blob
对象app
什么是 Blob?传送门dom
如今的状况是接口返回了pdf的URL,而后我要用这个url获取对应PDF的blob。函数
怎么作?固然是 ajax
。this
直接贴上代码:
const getPdfBlob = (url: string) => { return new Promise((resolve, reject)=> { let xhr = new XMLHttpRequest() xhr.open('get', url+'?t='+Math.random(), true); xhr.setRequestHeader('Content-Type', `application/pdf`); xhr.responseType = 'blob'; xhr.onload = function () { if (this.status == 200) { //接受二进制文件流 var blob = this.response; resolve(blob); } } xhr.send(); }) }
首先,写一个原生的 XMLHttpRequest
,方法为 get,url 中的 t 参数是为了阻止缓存。而后设置 responseType
为 blob,最后接受回来的就是 blob 数据。
为了后面批量使用,getPdfBlob
函数内部用 promise 包了一下。
使用方法:
getPdfBlob(url).then(blob => { saveAs(blob, filename);// 拿到 blob 并下载 pdf })
单独下载搞定!
首先,批量下载要压缩成zip包以后下载,因此要用到 jszip
。
这里写了一个将批量文件压缩为一个zip的方法:
import JSZip from 'jszip' import { saveAs } from 'file-saver'; getMultiZip(blobs)=> { var zip = new JSZip(); blobs.forEach(blob=> { // 添加要压缩的pdf zip.file('单个pdf文件名.pdf', blob, { binary:true }); }) zip.generateAsync({type:'blob'}).then(function(content) { //生成zip并保存 saveAs(content, '批量pdf文件名.zip'); }); }
有了这个方法以后,接下来批量获取 blob。
单独下载须要发起一个 ajax,批量下载,就要每一个 URL 都发起 ajax。
由于前面的 getPdfBlob
包装了promise,因此批量获取就能够这样写:
Promise.all( pdfUrlList.map(url=> getPdfBlob(url)) ).then(res=> { // res结构:[blob, blob, blob, ...] getMultiZip(res) })
这里用 Promise.all
的好处是能够并行发起请求,等最后一个请求结束后拿到全部的 blob,比循环执行 ajax 高效的多。
批量下载搞定!