前端下载文件的方法(同步,异步)

根据业务需求和后端返回的数据选择对应的方法。想要先预览,不立即下载选择异步方法;没有特殊要求一般都用a链接直接下载文件。

同步:使用a链接,直接下载文件

function handleExport() {
  //获取表单对象,antd的用法
  let value = getForm().getFieldsValue(); 
  // 调用api获取文档流
  exportEntryReport(value).then((res) => {
    const blobData = new Blob([res], {
      type: 'application/vnd.ms-excel',
    });
    //创建一个空的 a 标签
    const downloadA = document.createElement('a');
    // 将 blob 文件转化为 url 格式并赋值给a标签的 href 属性
    downloadA.href = URL.createObjectURL(blobData);
    // 给a标签设置下载链接并命名
    downloadA.setAttribute('download', '进场统计表.xlsx');
    // 点击事件触发 href
    downloadA.click();
  });
}

异步:获取code,用code换取下载地址,文件页面单独打开

1、封装下载的方法

// download.ts

//打开新窗口并访问指定的 URL的方法
//target:目标窗口的上下文或名称,默认为 "__blank",即在新标签页打开。
//noopener:是否要添加 noopener 属性,默认为 true。noopener 是一个安全性设置,用于防止新打开的页面操作原始页面的 window 对象。
//noreferrer:是否要添加 noreferrer 属性,默认为 true。noreferrer 是另一个安全性设置,用于防止新打开的页面发送 Referer 头信息,从而隐藏来源地址。
export function openWindow(
  url: string,
  opt?: { target?: string; noopener?: boolean; noreferrer?: boolean },
) {
  const { target = '__blank', noopener = true, noreferrer = true } = opt || {};
  const feature: string[] = [];
  //通过传入可选的参数来设置是否添加 noopener 和 noreferrer 等窗口特性
  noopener && feature.push('noopener=yes');
  noreferrer && feature.push('noreferrer=yes');

  window.open(url, target, feature.join(','));
}


//url:要下载的文件的 URL。
//target:目标窗口的上下文,默认为 '_blank',即在新标签页中下载。
//fileName:要保存的文件名,默认为 undefined。
export function downloadByUrl({
  url,
  target = '_blank',
  fileName,
}: {
  url: string;
  target?: string;
  fileName?: string;
}): boolean {
  //1、判断用户浏览器的类型
  //通过 navigator.userAgent 来判断是否为 Chrome 浏览器或 Safari 浏览器
  const isChrome = window.navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
  const isSafari = window.navigator.userAgent.toLowerCase().indexOf('safari') > -1;
  //如果是 iOS 设备返回 false,因为 iOS 不支持直接下载
  if (/(iP)/g.test(window.navigator.userAgent)) {
    console.error('Your browser does not support download!');
    return false;
  }
  //对于 Chrome 和 Safari 浏览器,创建一个 <a> 元素
  if (isChrome || isSafari) {
    const link = document.createElement('a');
    link.href = url;
    link.target = target;
    //检查浏览器是否支持下载属性来决定是否设置下载文件的名称。如果 link.download 存在(即浏览器支持下载属性),则将其设置为传入的 fileName 值或从 URL 中提取的文件名
    if (link.download !== undefined) {
      link.download = fileName || url.substring(url.lastIndexOf('/') + 1, url.length);
    }
    //如果浏览器支持 document.createEvent,则创建一个 MouseEvents 事件,将其分派给 <a> 元素,触发文件下载
    if (document.createEvent) {
      const e = document.createEvent('MouseEvents');
      e.initEvent('click', true, true);
      link.dispatchEvent(e);
      return true;
    }
  }
  //如果浏览器不是 Chrome 或 Safari,或者不支持 document.createEvent,则判断 URL 是否已经包含查询参数 '?'。如果没有查询参数,则在 URL 后面添加 '?download',作为下载标识
  if (url.indexOf('?') === -1) {
    url += '?download';
  }
  //最后,调用之前提到的 openWindow 函数,打开带有下载标识的 URL,并传入目标窗口的上下文。然后返回 true,表示下载操作已经开始
  openWindow(url, { target });
  return true;
}

2、页面中使用

先创建一个变量用来声明计时器。

先获取code,用code调后端接口获取address字段,如果是200说明没获取到下载链接,使用setTimeout计时器三秒后再次调接口查找,这样轮询直到拿到。

获取到地址后,使用上面封装好的方法实现文件预览和下载。

//获取code
let timer: NodeJS.Timeout;
function handleExport() {
  let params = {
    ...getForm().getFieldsValue(),
  };
  exportVehicles(params).then((res) => {
    if (res.code == 200) {
      const paramCode = res.data?.code;
      message.success('正在导出');
      handlePollingExportValue(paramCode);
    } else {
      message.error(res.message);
    }
  });
}

//用code换取下载地址
function handlePollingExportValue(paramCode) {
  let params = {
    code: paramCode,
  };
  isSyncing.value = true;
  downloadVehicles(params).then(({ data, code }) => {
    const address = data?.address;
    if (code == 200) {
      if (address == 200) {
        timer = setTimeout(() => {
          handlePollingExportValue(paramCode);
        }, 3000);
      } else {
        if (address) {
          downloadByUrl({
            url: address,
            target: '_self',
          });
        } else {
          message.error('找不到错误地址');
        }
        isSyncing.value = false;

        message.success('导出文件下载完成');
        clearTimeout(timer);
      }
    } else {
      isSyncing.value = false;
    }
  });
}

在 TypeScript 中,let timer: NodeJS.Timeout; 表示声明了一个名为 timer 的变量,并指定其类型为 NodeJS.Timeout。

NodeJS.Timeout 是 Node.js 提供的一个类型,它表示一个定时器的句柄。当使用 setTimeout 或 setInterval 函数创建定时器时,返回的值就是 NodeJS.Timeout 类型,可以将其赋值给 timer 变量。通过这样的声明,可以在后续的代码中使用 timer 变量来管理定时器,例如取消定时器或者清除已经存在的定时器。

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
前端开发中,我们经常会遇到需要处理异步操作的情况。异步操作是指不会阻塞代码执行的操作,例如发送网络请求、读取文件等。而同步操作则是会阻塞代码执行的操作。 为了解决异步操作带来的问题,我们可以使用回调函数、Promise、async/await等方式将异步代码转换为同步代码。 1. 回调函数:通过在异步操作完成后执行指定的回调函数来处理异步结果。例如: ```javascript function fetchData(callback) { setTimeout(function() { const data = '异步数据'; callback(data); }, 1000); } fetchData(function(data) { console.log(data); }); ``` 2. Promise:Promise 是一种用于处理异步操作的对象。它可以表示一个异步操作的最终完成或失败,并返回结果或错误信息。例如: ```javascript function fetchData() { return new Promise(function(resolve, reject) { setTimeout(function() { const data = '异步数据'; resolve(data); }, 1000); }); } fetchData().then(function(data) { console.log(data); }); ``` 3. async/await:async/await 是基于 Promise 的一种异步编程模型,使得异步代码看起来像同步代码,更易于理解和维护。例如: ```javascript function fetchData() { return new Promise(function(resolve, reject) { setTimeout(function() { const data = '异步数据'; resolve(data); }, 1000); }); } async function fetchDataAsync() { const data = await fetchData(); console.log(data); } fetchDataAsync(); ``` 这些是常见的解决异步操作的方式,根据具体需求和项目情况,选择合适的方式来处理异步操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值