小张是一名刚入职的前端开发工程师,某天,他的领导给他布置了一个看似简单的任务:
让用户能够通过文件链接下载多个文件
小张信心满满,觉得这不过是个小问题。然而,当他真正动手时,才发现这个需求并不简单。不同的下载方式各有优缺点,甚至有些方法会带来意想不到的问题,他决定一一尝试,探索最优解。
方案一:window.open
——简单粗暴,但会打开新标签页
小张首先想到的是 window.open(url)
,它可以让浏览器直接打开下载链接。
window.open('https://example.com/file.pdf');
优点:
- 代码简单,直接调用即可。
- 适用于单个文件的下载。
缺点:
- 每次下载都会打开一个新的浏览器标签页,影响用户体验。
- 部分浏览器可能会拦截
window.open
,导致下载失败。
方案二:window.location.href
简单有效,但不能同时下载多个文件
小张发现,window.location.href
也可以实现下载,且不会打开新标签页。
window.location.href = 'https://example.com/file.pdf';
优点:
- 适用于单文件下载。
- 不会像
window.open
那样打开新页面。
缺点:
- 无法循环下载多个文件。如果连续多次赋值
window.location.href
,后一个请求会覆盖前一个,导致只能下载最后一个文件。
方案三:iframe
支持多文件下载,但无法监听完成状态
为了让多个文件能够顺利下载,小张尝试用 iframe
。
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
标签下载。
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 文件下载。
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
打包文件的方案,因为它不仅解决了多个文件下载时图标显示的问题,还提高了用户体验,让下载更加流畅,没有哪个方案比另外一个方案好,只有最适合的方案,根据实际的场景能满足需求最优解就是最好的。