4

背景

最近有一个单独和批量下载 pdf 的文件的需求。单独下载首先想到的是用 a 标签 download 属性直接下载。实践中发现,浏览器会默认打开pdf文件,而不是直接下载。批量下载需要压缩,这一步也需要在前端实现。

这里记录下我的实现方式。适用于绝大部分文件。

准备工作

这里用到了两个 npm 包:

  • jszip
  • file-saver

jszip 用于压缩。file-saver 用于在前端保存文件。

npm install file-saver jszip --save

安装好之后,先实现单独下载。

单独下载

单独下载 pdf,只用 file-saver 就可以了。

import { saveAs } from 'file-saver';

function save() {
    saveAs(blob, filename);
}

saveAs 方法有两个参数,第二个参数是下载的文件名,第一个参数就比较难获取了,是一个 Blob 对象

什么是 Blob?传送门

现在的情况是接口返回了pdf的URL,然后我要用这个url获取对应PDF的blob。

怎么做?当然是 ajax

ajax 获取blob

直接贴上代码:

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 高效的多。

批量下载搞定!


杨成功
3.9k 声望12k 粉丝

分享小厂可落地的前端工程与架构