1、简单下载
通过a标签或者iframe实现下载,缺点是必须先将文件下载完成后才会弹出保存弹窗,适用于小文件下载保存(图片保存等)
export const download = (url, fileName = "") => {
if (!fileName) {
fileName = url.substring(url.lastIndexOf("/") + 1);
}
// 创建一个<a>标签
const element = document.createElement("a");
// 设置href属性为下载链接
element.setAttribute("href", url);
// 设置download属性为文件名
element.setAttribute("download", fileName);
// 将<a>标签添加到DOM中
document.body.appendChild(element);
// 模拟点击<a>标签开始下载
element.click();
// 从DOM中移除<a>标签
document.body.removeChild(element);
};
2、普通下载
- 利用Electron的dialog.showSaveDialogSync方案拿到保存路径 或者 使用默认保存路径
- 然后利用axios或者fetch下载文件
- 最后使用node的fs写入文件
对比方案1:
- 优点:可以先选择保存路径再下载,可以处理下载过程中的相关错误
- 缺点:无法实现暂停下载或者继续下载,无法下载大文件(缓存buffer时有内存上限)
3、高级下载
利用Electron中webContents.downloadURL实现下载方案
- 优点:自带支持暂停下载,继续下载,取消下载,重新下载,基本符合所有下载场景
// 在主进程中.
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
win.webContents.session.on('will-download', (event, item, webContents) => {
// 无需对话框提示, 直接将文件保存到路径
item.setSavePath('/tmp/save.pdf')
item.on('updated', (event, state) => {
if (state === 'interrupted') {
console.log('Download is interrupted but can be resumed')
} else if (state === 'progressing') {
if (item.isPaused()) {
console.log('Download is paused')
} else {
console.log(`Received bytes: ${item.getReceivedBytes()}`)
}
}
})
item.once('done', (event, state) => {
if (state === 'completed') {
console.log('Download successfully')
} else {
console.log(`Download failed: ${state}`)
}
})
})
- 踩坑:will-download在渲染进程中使用时 批量下载可能会导致无法拿到downloadItem.on('done')相关回调,或者出现ipc 通信崩溃(Electron 22)。建议在主进程中使用.
- 缺点:暂停下载时,退出应用后再启动需要重新下载 无法继续
进阶版下载
解决方案3 退出应用后无法继续下载的问题
- 通过改造方案2去实现相关需求
- 在方案2的基础上加入分片下载 response.headers.get('Content-Range'),分片下载可以解决,暂停继续下载功能,结合使用fs.append 追加文件写入。同时利用electron-store将下载进度保存到本地磁盘中可实现退出应用后还可以继续下载
哪种方案最佳
- 方案3 可实现绝大部分需求 二次封装工作量小
- 方案4 二次分装工作量较大,功能完善
- 测试过程中方案4的下载速度比方案3 electron api下载速度快