背景
最近有个需求,希望实现批量下载功能。不涉及后端接口,前端直接拿文件路径下载,踩了2个坑,特此记录,抚慰心灵。
遇到的问题
- 一开始直接循环,下载,总是默认下载最后一个文件
- 使用setTimeout代码报错
实现
通过循环选中的路径数组,动态创建a标签,进行下载
初始代码(有问题)
// .vue文件
// js
import { downloadFile } from '@/utils';
methods:{
// 批量下载
batchDownload(){
paths.forEach((item,index) => { // 循环路径数组
const url = `${basePicUrl}${item}` // 拼接出下载路径 eg: http://10.110.xx:0000/img/a.zip
downloadFile(url,names[index]) // 执行下载方法(动态生成a标签方式)
})
}
}
// util.js 文件
// 下载
export function downloadFile(url,name) {
const a = document.createElement('a')
a.download = name || new Date().getTime()
a.href = url
a.click()
a.remove()
}
结果总是默认下载最后一个文件,中间走了很多弯弯绕绕,以为是文件太大的原因,甚至去试了streamSaver.js(大文件下载处理,处理流文件,而我这里直接是文件存储路径下载),万万没想到啊,静下心来想想,发现方向都是错的。。
后来查到原因,当循环执行下载的时候,几个下载命令连续执行的时候,浏览器会取消上一个下载,直接下载最后一个文件。
所以要加一个定时器,让几个连续的下载请求之间有时间间隔
于是
paths.forEach((item,index) => {
const url = `${basePicUrl}${item}` // 拼接出下载路径 eg: http://10.110.xx:0000/img/a.zip
setTimeout(downloadFile(url,names[index]),1000*index)
})```
结果setTimeout上面的代码一直报错,就很奇怪,最后,是我setTimeout用错了,竟然用错了,我盲目自信了。。setTimeout回调函数传参不是我以为的方式
参考文章:https://zhuanlan.zhihu.com/p/110274000
setTimeout中this指向问题:https://wangdoc.com/javascript/async/timer
修改后代码(正确)
paths.forEach((item,index) => {
const url = `${basePicUrl}${item}` // 拼接出下载路径 eg: http://10.110.xx:0000/img/a.zip
setTimeout(()=>{ // 修改了setTimeout传参方式
downloadFile(url,names[index])
},1000*index)
})```
至此,完美,批量下载实现