前端实现下载文件(包含压缩包下载)方式汇总

前端实现下载文件(包含压缩包下载)方式汇总

码农世界 2024-06-04 前端 91 次浏览 0个评论

默认最简单的下载方式是:window.open(后台接口API路径),但该方法弊端:因是新开窗口方式,前端展示上,每次会闪下。

此外,如果使用window.open(文件URL)方式:

  • pdf、office文档、psd:直接下载。
  • 图片、txt:新开窗口预览,不会下载;且txt预览,有时出现中文乱码问题。

    一、根据文件URL下载

    实现原理:通过a标签实现下载。

    /**
     * @method 下载单个文件(文件类型可任意:.png、txt、office文档、.psd等)
     * @param { String } url - 文件的http完整路径, 如:http: //xxx.png
     * @param { String } fileName - 文件名,注意是要带文件后缀名,如:xxx.png
     * @doc https://blog.csdn.net/weixin_39547158/article/details/110851570
     */
    export function downloadFile(url: string, fileName: string) {
      return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.responseType = 'blob';
        xhr.upload.onprogress = (e) => {
          if (e.lengthComputable) {
            let progress = e.loaded / e.total;
            console.log('文件上传进度是', progress);
          }
        };
        xhr.onload = function () {
          const url = window.URL.createObjectURL(xhr.response);
          const eleLink = document.createElement('a');
          eleLink.href = url;
          eleLink.download = `${fileName}`;
          eleLink.style.display = 'none';
          document.body.appendChild(eleLink);
          eleLink.click();
          document.body.removeChild(eleLink);
          resolve('success');
        };
        xhr.onerror = (e) => {
          console.log('请求错误回调', e);
          message.warning('下载文件失败')
          reject(e);
        };
        xhr.send();
      });
    }

    二、excel文件:调用后台接口返回文件流,前端下载文件

    实现原理:调用后台接口,返回blob, 前端使用file-saver库实现下载。

    // 下载excel文件
    import FileSaver from 'file-saver';
    const downloadTemplate = async () => {
      try {
        const params = { ... } // 传参
        const res = await generateDownStreamReconciliationUsingGET(params);
        // res为返回结果
        if (res) {
          const blob = new Blob([res], { type: 'application/vnd.ms-excel' });
          FileSaver.saveAs(blob, '对账单.xlsx');
          console.log('对账单下载成功')
        }
      } catch (e) {
        console.log(e);
      } finally {
        console.log('finally')
      }
    };
    // 生成对账excel模板表格API
    export async function generateDownStreamReconciliationUsingGET(
      params: API.generateDownStreamReconciliationUsingGETParams,
      options?: { [key: string]: any },
    ) {
      return request(
        `${process.env.APP_HOST_WAYBILL}/xxx/generateDownStreamReconciliation`,
        {
          method: 'GET',
          responseType: 'blob',  // 必须写该行,否则:后台返回的是string,不是blob且文件下载后,会出现打不开问题。
          params: {
            ...params,
          },
          ...(options || {}),
        },
      );
    }

    三、多文件URL下载,前端生成压缩包下载

    实现原理:jszip库 + file-saver库

    import { getBlobOfUrl } from '@/services/common';
    import { saveAs } from 'file-saver';
    import JSZip from 'jszip';
    import { message } from 'antd';
    /**
     * @method 同时下载多文件,并生成一个压缩包
     * @param { Object[] } fileInfoList - 文件列表
     * @param { String } urlField - 文件URL的字段名
     * @param { String } fileNameField - 文件名的字段名
     * @param { String } folderName - 压缩包 & 文件夹名称
     */
    export function downloadAsZip(
      fileInfoList: any[],
      folderName = '文件压缩包',
      urlField = 'filePath',
      fileNameField = 'name',
    ) {
      return new Promise((resolve, reject) => {
        const zip = new JSZip();
        // const folder = zip.folder(folderName); // 创建文件夹
        const promisesList = fileInfoList.map((item) => {
          return getBlobOfUrl(item[urlField])
            .then((data) => {
              // console.log(data); // Blob
              // folder.file(item[fileNameField], data, { binary: true }); // 往文件夹中存放文件
              zip.file(item[fileNameField], data, { binary: true }); // 不创建文件夹
            })
            .catch((e) => {
              console.log(e);
              message.warning(e?.message || '获取文件流失败')
            });
        });
        Promise.all(promisesList)
          .then(() => {
            zip
              .generateAsync({ type: 'blob' })
              .then((content) => {
                saveAs(content, folderName);
                resolve('success');
              })
              .catch((e) => {
                message.warning(e?.message || '生成压缩包失败')
                reject(e);
              });
          })
          .catch((e) => {
            message.warning(e?.message || '批量获取文件流失败')
            reject(e);
          });
      });
    }
    import { request } from 'umi';
    /**
     * @method 根据文件URL获取blob数据流的API
     * @param { String } fileUrl - 文件完整路径,如:http://xxx.png
     */
    export function getBlobOfUrl(fileUrl: string) {
      return request(fileUrl, {
        method: 'GET',
        responseType: 'blob', // 设置后台返回的内容类型为blob
        params: {
          notAuthorization: true,
        },
      });
    }

转载请注明来自码农世界,本文标题:《前端实现下载文件(包含压缩包下载)方式汇总》

百度分享代码,如果开启HTTPS请参考李洋个人博客
每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,91人围观)参与讨论

还没有评论,来说两句吧...

Top