条件:
1.有一个下载按钮
<button>下载</button>
2.有一个包含所有文件地址的数组
const urlArr = ['http://localhost:5000/1.zip', 'http://localhost:5000/2.zip']
问:如何在点击按钮后下载所有的文件?
有很多同学可能觉得很简单,循环数组,每次创建一个a标签,然后click下载不就完了吗?如下所示:
<button>下载</button>
<script>
function downloadFiles(urlArr) {
urlArr.forEach((url) => {
const fileName = url.split('/').pop()
const link = document.createElement('a')
link.href = url
link.download = fileName
link.style.display = 'none'
link.click()
})
}
const urlArr = ['http://localhost:5000/1.zip', 'http://localhost:5000/2.zip']
const btn = document.querySelector('button')
btn.addEventListener('click', () => downloadFiles(urlArr))
</script>
但经过测试,这种方法只能下载最后一个文件,如下图:
原因:
浏览器在处理多个文件下载时需要一些时间来完成每个下载操作。在循环中,当点击第一个链接时,浏览器开始下载该文件,但在下载完成之前,循环已经继续执行到下一个链接。因此,最终只有最后一个链接的下载操作能够完成。
解决方案:
可以使用异步操作或者延迟执行来确保每个文件下载完成后再进行下一个下载操作。具体代码如下:
<button>下载</button>
<script>
function downloadFile(url) {
return new Promise((resolve, reject) => {
const fileName = url.split('/').pop()
const link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.download = fileName
// 这个延迟操作的目的是为了确保浏览器有足够的时间来处理下载操作
// 这样可以避免在循环中快速触发多个下载操作,导致浏览器无法正确处理下载请求
link.addEventListener('click', () => {
setTimeout(() => {
resolve()
}, 100)
})
link.click()
})
}
async function downloadFiles(urlArr) {
for (const url of urlArr) {
await downloadFile(url)
}
}
const urlArr = ['http://localhost:5000/1.zip', 'http://localhost:5000/2.zip']
const btn = document.querySelector('button')
btn.addEventListener('click', () => downloadFiles(urlArr))
</script>