背景
使用以下简单的下载方法时,会发现只有第一个文件被下载了,而且没有任何提示。
用的Edge,使用以下方法下载多个文件没有任何提示。
如果用过alist,会发现那里面的批量下载也是个残废功能。
后续的方法主要是针对于没有提示的问题。
js
const a = document.createElement('a')
a.href = url
a.download = filename // 指定文件名
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
原因
浏览器出于安全或用户体验限制,阻止了"非用户直接触发"的多次自动下载。
单次click对应一次下载,浏览器发现你只点了一次按钮,却触发多次下载,于是阻止。
尤其是使用如上简单代码下载时,居然连提示都没有跳出来。
解决
任何一种解决办法都需要用户在浏览器上允许下载多个文件,除非你把多个文件打成压缩包,避开这个问题。
直接下载
通过setTimeout可以触发浏览器下载多个文件的提示。
不跳出下载多文件的提示不是我瞎说的,我遇到这种情况很多次,下面的这种延时下载可以绕过这个问题。
如果在100ms以内,依然只下载一个文件。(我没详细测过,200是可以的) 当不使用setTimeout时,会使得浏览器完全不跳出多文件下载的提示,导致用户不会授权 最终后果就是只下载第一个文件
js
setTimeout(() => {
const a = document.createElement('a')
a.href = url // 直接使用原始URL,而非Blob URL
a.download = filename // 指定文件名
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
}, timeout)
timeout += 200
所有文件都开始下载后,应该清空timeout。
fetch + Blob(推荐)
优点:对于跨域资源,也能够实现自定义命名。
这种方式的主要缺点在于用户无法看到下载的进度条,因为没有调用浏览器的下载器进行下载 或者说需要手动实现下载进度显示功能
js
fetch(url)
.then(res => res.blob())
.then(blob => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename; // ✅ 生效!因为是 Blob URL
a.click();
URL.revokeObjectURL(url);
document.body.removeChild(a)
});