前端文件下载全攻略:从单文件到批量下载,哪种方法最优?

小张是一名刚入职的前端开发工程师,某天,他的领导给他布置了一个看似简单的任务:

让用户能够通过文件链接下载多个文件

小张信心满满,觉得这不过是个小问题。然而,当他真正动手时,才发现这个需求并不简单。不同的下载方式各有优缺点,甚至有些方法会带来意想不到的问题,他决定一一尝试,探索最优解。

方案一:window.open------简单粗暴,但会打开新标签页

小张首先想到的是 window.open(url),它可以让浏览器直接打开下载链接。

js 复制代码
window.open('https://example.com/file.pdf');

优点

  • 代码简单,直接调用即可。
  • 适用于单个文件的下载。

缺点

  • 每次下载都会打开一个新的浏览器标签页,影响用户体验。
  • 部分浏览器可能会拦截 window.open,导致下载失败。

方案二:window.location.href 简单有效,但不能同时下载多个文件

小张发现,window.location.href 也可以实现下载,且不会打开新标签页。

js 复制代码
window.location.href = 'https://example.com/file.pdf';

优点

  • 适用于单文件下载。
  • 不会像 window.open 那样打开新页面。

缺点

  • 无法循环下载多个文件 。如果连续多次赋值 window.location.href,后一个请求会覆盖前一个,导致只能下载最后一个文件。

方案三:iframe 支持多文件下载,但无法监听完成状态

为了让多个文件能够顺利下载,小张尝试用 iframe

js 复制代码
function downloadFile(url) {
  const iframe = document.createElement('iframe');
  iframe.style.display = 'none';
  iframe.src = url;
  document.body.appendChild(iframe);
  setTimeout(() => {
    document.body.removeChild(iframe);
  }, 5000); // 延迟移除 iframe,防止影响下载
}

优点

  • 适用于多文件下载。

缺点

  • iframe 无法监听文件下载是否完成。
  • 需要在合适的时机移除 iframe,否则可能会影响页面性能。

方案四:fetch + blob------最优雅的下载方式

小张最终发现,fetch 可以获取文件数据,再通过 Blob 处理并使用 a 标签下载。

js 复制代码
async function downloadFile(url, fileName) {
  const response = await fetch(url);
  if (!response.ok) throw new Error('Download failed');
  const blob = await response.blob();
  const blobUrl = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = blobUrl;
  a.download = fileName;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  URL.revokeObjectURL(blobUrl);
}

function download(fileList){
   for(const file of fileList) {
     await downloadFile(file.url,file.name)
   }
}

优点

  • 不会打开新标签页。
  • 可以同时下载多个文件。
  • 适用于现代浏览器,兼容性较好。

缺点

  • 需要处理异步 fetch 请求。
  • 服务器必须支持跨域资源共享(CORS),否则 fetch 请求会失败。
  • 多次文件下载会导致多个浏览器下载图标 :每次调用 a.click() 时,浏览器都会显示一个下载图标,影响用户体验。

方案五:jsZip 打包多个文件为 ZIP 下载------避免多次下载图标

为了进一步优化方案四,避免浏览器每次下载时显示多个下载图标,小张决定使用 jsZip 插件将多个文件打包成一个 ZIP 文件下载。

js 复制代码
import JSZip from 'jszip';

async function downloadFilesAsZip(files) {
  const zip = new JSZip();
  // 循环遍历多个文件,获取每个文件的数据
  for (const file of files) {
    const response = await fetch(file.url);
    if (!response.ok) throw new Error(`Failed to fetch ${file.name}`);
    const blob = await response.blob();
    zip.file(file.name, blob); // 将文件添加到 ZIP 包中
  }

  // 生成 ZIP 文件并触发下载
  zip.generateAsync({ type: "blob" })
    .then(function(content) {
      const a = document.createElement('a');
      const blobUrl = URL.createObjectURL(content);
      a.href = blobUrl;
      // 给压缩包设置下载文件名
      a.download = 'files.zip';
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      // 释放 URL 对象
      URL.revokeObjectURL(blobUrl);
    });
}

优点

  • 提升用户体验:用户下载一个压缩包后,只需解压就可以获取所有文件,避免了多次点击和等待的麻烦。
  • 适用于多文件下载:非常适合需要批量下载的场景。

缺点

  • 浏览器对大文件的支持:如果要下载的文件非常大,或者文件总大小很大,可能会导致内存消耗过高,甚至在浏览器中崩溃。
  • 下载速度受限于压缩处理:打包文件为 ZIP 需要时间,尤其是文件较多时,会稍微影响压缩的速度,只适用于文件不是很大且数量不是很多的时候

结语:小张的最终选择

经过一番探索,小张最终选择了 jsZip 打包文件的方案,因为它不仅解决了多个文件下载时图标显示的问题,还提高了用户体验,让下载更加流畅,没有哪个方案比另外一个方案好,只有最适合的方案,根据实际的场景能满足需求最优解就是最好的。

相关推荐
Yolo@~2 小时前
个人网站:基于html、css、js网页开发界面
javascript·css·html
斯~内克2 小时前
Electron 菜单系统深度解析:从基础到高级实践
前端·javascript·electron
数据知道2 小时前
【YAML】一文掌握 YAML 的详细用法(YAML 备忘速查)
前端·yaml
dr李四维2 小时前
vue生命周期、钩子以及跨域问题简介
前端·javascript·vue.js·websocket·跨域问题·vue生命周期·钩子函数
旭久2 小时前
react+antd中做一个外部按钮新增 表格内部本地新增一条数据并且支持编辑删除(无难度上手)
前端·javascript·react.js
windyrain2 小时前
ant design pro 模版简化工具
前端·react.js·ant design
浪遏2 小时前
我的远程实习(六) | 一个demo讲清Auth.js国外平台登录鉴权👈|nextjs
前端·面试·next.js
GISer_Jing3 小时前
React-Markdown详解
前端·react.js·前端框架
太阳花ˉ3 小时前
React(九)React Hooks
前端·react.js