当前位置: 首页 > Web前端 > HTML

【电子乐园系列】文件下载

时间:2023-04-02 14:00:17 HTML

作者:long.woo文件下载是我们开发中比较常见的业务需求,比如导出excel。下载Web应用程序文件有一些限制。通常,后端将响应的头部信息更改为Content-Disposition:attachment;filename=xxx.pdf来触发浏览器的下载行为。electron中的下载行为会触发会话的will-download事件。在这个事件中,可以获得downloadItem对象,通过downloadItem对象可以实现一个简单的文件下载管理器:1.如何触发下载由于electron是基于chromium实现的,调用webContents的downloadURL方法就相当于调用chromium的底层实现对于下载,会忽略响应头信息,触发will-download事件。//触发下载win.webContents.downloadURL(url)//监听will-downloadsession.defaultSession.on('will-download',(event,item,webContents)=>{})2.下载流程3.功能设计与实现一个简单的文件下载管理器功能包括:设置保存路径暂停/恢复和取消下载进度下载速度下载完成打开文件和打开文件位置文件图标下载记录3.1设置保存路径如果没有设置保存路径,electron会自动弹出系统保存对话框。如果不想使用系统的保存对话框,可以使用setSavePath方法。当有同名文件时,会直接覆盖下载。item.setSavePath(path)允许用户选择保存位置操作,以获得更好的用户体验。当点击location输入框时,渲染进程通过ipc与主进程通信,打开系统文件选择对话框。主要流程实现代码:/***打开文件选择框*@paramoldPath-最后打开的路径*/constopenFileDialog=async(oldPath:string=app.getPath('downloads'))=>{if(!win)returnoldPathconst{canceled,filePaths}=awaitdialog.showOpenDialog(win,{title:'选择保存位置',properties:['openDirectory','createDirectory'],defaultPath:oldPath,})return!canceled?filePaths[0]:oldPath}ipcMain.handle('openFileDialog',(event,oldPath?:string)=>openFileDialog(oldPath))渲染过程代码:constpath=awaitipcRenderer.invoke('openFileDialog','PATH')3.2pause/Resume和cancel获取downloadItem后,pause、resume和cancel分别调用pause、resume和cancel方法。当我们要删除列表中正在下载的项目时,需要先调用cancel方法取消下载。3.3下载进度监听DownloadItem中的更新事件,可以实时获取下载的字节数据,计算下载进度和每秒下载速度。//计算下载进度constprogress=item.getReceivedBytes()/item.getTotalBytes()下载时,我想在Mac系统的dock和Windows系统的任务栏上显示下载信息,例如:数字ofdownloads:通过app的badgeCount属性设置,为0时不显示。也可以通过dock的setBadge方法设置。此方法支持字符串。如果不显示,需要设置为''。下载进度:通过窗口的setProgressBar方法设置。由于Mac和Windows系统之间的差异,下载计数仅适用于Mac系统。添加process.platform==='darwin'条件,避免在非Mac和Linux系统下出现异常错误。下载进度(Windows系统托盘,Mac系统dock)显示效果://macdock显示下载次数://方法一app.badgeCount=1//方法二app.dock.setBadge('1')//macdock和windows任务栏显示进度win.setProgressBar(progress)3.4下载速度由于downloadItem没有直接给我们提供获取下载速度的方法或者属性,所以需要我们自己实现。思路:在updated事件中,使用getReceivedBytes方法获取本次下载的字节数据减去上次下载的字节数据。//记录上次下载的字节数据letprevReceivedBytes=0item.on('updated',(e,state)=>{constreceivedBytes=item.getReceivedBytes()//计算每秒下载速度downloadItem.speed=receivedBytes-prevReceivedBytesprevReceivedBytes=receivedBytes})需要注意的是,更新事件每500ms执行一次。3.5下载完成当一个文件下载完成、中断或取消时,需要通过监听downloadItem的done事件通知渲染进程修改状态。item.on('done',(e,state)=>{downloadItem.state=statedownloadItem.receivedBytes=item.getReceivedBytes()downloadItem.lastModifiedTime=item.getLastModifiedTime()//通知渲染进程并更新下载状态webContents.send('downloadItemDone',downloadItem)})3.6打开文件并打开文件所在位置使用electron的shell模块实现文件的打开(openPath)和文件所在位置(showItemInFolder)。由于openPath方法支持返回值Promise,当不支持打开文件时,系统会进行相应提示,而showItemInFolder方法的返回值为void。如果需要更好的用户体验,可以使用nodejs的fs模块先检查文件是否存在。importfsfrom'fs'//打开文件constopenFile=(path:string):boolean=>{if(!fs.existsSync(path))returnfalseshell.openPath(path)returntrue}//打开文件位置constopenFileInFolder=(path:string):boolean=>{if(!fs.existsSync(path))returnfalseshell.showItemInFolder(path)returntrue}3.7文件图标使用app模块的getFileIcon方法很方便获取系统关联的文件图标返回一个Promise类型,我们可以通过toDataURL方法将其转为base64,不需要我们针对不同的文件类型显示不同的图标。constgetFileIcon=async(path:string)=>{consticonDefault='./icon_default.png'if(!path)Promise.resolve(iconDefault)consticon=awaitapp.getFileIcon(path,{size:'normal'})returnicon.toDataURL()}3.8下载记录随着下载的历史数据越来越多,使用electron-store将下载记录保存到本地。对电子感兴趣?请关注我们的开源项目ElectronPlayground,带你快速上手Electron。每周五我们都会挑选一些有趣的文章和新闻与大家分享。快来关注我们的小风周刊吧。我们是好未来小黑板的前端技术团队。我们会经常与您分享最新最酷的行业技术知识。欢迎知乎、掘金、Segmentfault、CSDN、简书、开源中国、博客园关注我们。