• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

react项目多个文件压缩成zip下载

武飞扬头像
Jason秀啊
帮助1

假设后端给了你20个文件url,前端如果一次下载一个,下载20次,浏览器底部将非常壮观,这不是一个优秀的前端。优秀的前端很容易想到将这些文件压缩成一个zip,这样就只需要下载一次就够了,设计非常的人性。

核心

1. bluebird // Promise扩展库
2. file-saver // 客户端保存文件的解决方案
3. JsZip // js创建、读取和编辑 .zip 文件

如何实现

html:

<Button type="primary" onClick={() => batchDownload(selectedRows)}>
  批量下载
</Button>

ts:

// url -> blob
const fetchBlob = (res: { url: string; filename: string }) => {
  // 原生fetch请求文件,拿到blob
  return fetch(res.url).then((resp) => ({
    blob: resp.blob(),
    filename: res.filename,
  }));
};



// 最终导出zip
const exportZip = (res: Array<{ blob: Promise<Blob>; filename: string }>) => {
  // 创建zip实例
  const zip = JsZip();
  // 向zip中添加文件(二进制文件流)
  res.forEach((item) => {
    zip.file(item.filename, item.blob);
  });
  // 异步生成zip,成功后下载zip
  zip
    .generateAsync({ type: 'blob' })
    .then((zipFile) =>
      FileSaver.saveAs(zipFile, 'xxx.zip'),
    );
};




// 点击批量下载按钮,records为选中的需要下载文件信息的集合
const batchDownload = (
  records: api.GetV1ContractModelGetContractListResponse['records'],
) => {
  if (records && records.length) {
  
    // -------- 判断文件名是否重复 ----------
    const personNames: string[] = [];
    let current = 0;
    const findIndex = (name: string) => {
      if (personNames.includes(name)) {
        current  = 1;
        findIndex(`${name}-${current}`);
      } else {
        current = 0;
        personNames.push(name);
      }
      const res = personNames[personNames.length - 1].split('-');
      return res.length > 1 ? res[res.length - 1] : -1;
    };
    // -------- 判断文件名是否重复 ----------
    
    // Promise.map: http://bluebirdjs.com/docs/api/promise.map.html
    Promise.map(
      records.map((item) => {
        const arr = item.ossUrl.split('.');
        const surfix = arr[arr.length - 1]; // 文件后缀名
        let filename = '';
        const index = findIndex(item.personName);
        if (index !== -1) {
          // 文件名重复,重复的文件名将不会被下载下来 so bad😒,所以要加个索引标记😄
          filename = `xxx(${index}).${surfix}`;
        } else {
          // 文件名没有重复
          filename = `xxx.${surfix}`;
        }
        // 这里return出去的对象将被Promise.map的第二个参数所接收
        return { url: item.ossUrl, filename };
      }),
      async (res: { url: string; filename: string }) => {
        // 所有return出去的对象将被组装成数组后被Promise.map成功的回调函数(.then)接收
        return await fetchBlob(res);
      },
      { concurrency: 5 },
    ).then((res: Array<{ blob: Promise<Blob>; filename: string }>) => {
      exportZip(res);
    });
  } else {
    message.warning('请选择要下载的文件');
  }
};
学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgaekgb
系列文章
更多 icon
同类精品
更多 icon
继续加载