一、前言
本文主要介绍electron应用的dialog模块的适用场景,主要包括下载保存、文件上传、消息提示等场景。其中上传下载配合使用node的request模块。
二、实施内容
1.实现下载功能
这里我们主要用到的是electron的dialog模块中的showSaveDialog
方法。主要实现方式如下,这里我们创建一个ElectronDownloadFile.js文件,用于封装下载方法
import { ipcMain, dialog } from 'electron'
import path from 'path'
const fs = require('fs')
const request = require('request')
let _win // 当前窗口实例
let isMac = process.platform === 'darwin' // 判断是否为macOS
export function downloadFile (win) {// 解决M1芯片可能会报证书失效问题process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'_win = win// 创建监听事件,接收来自渲染进程的下载请求// file参数为一个对象{name: '文件名,例***.jpg', url: '文件远端路径'}ipcMain.on('downloadFile', (event, file) => {/*为解决文件名包含特殊字符引起无发下载 --- start */var reg = /\\|\/|\?|\?|\*|\"|\“|\”|\'|\‘|\’|\<|\>|\{|\}|\[|\]|\[|\]|\:|\:|\^|\$|\!|\~|\`|\|/gconst fileNameSplitArr = file.name.split('/')fileNameSplitArr[fileNameSplitArr.length - 1] = fileNameSplitArr[fileNameSplitArr.length - 1].replace(reg, '')file.name = fileNameSplitArr.join('')/*为解决文件名包含特殊字符引起无发下载 --- end */// 这里设置了保存弹出框的默认名称(如下图1),设置openDirectory表示可以选择文件夹dialog.showSaveDialog(win, { defaultPath: file.name, properties: ['openDirectory'] }).then(result => {// 承载文件源地址const fileURL = file.url// 这里获取用户通过弹框做选择的保存至本地的地址if (result.filePath.length !== 0) {let localPath = result.filePathif (!isMac) { // 处理windows系统反斜杠问题const arr = localPath.split(path.sep)localPath = arr.reduce((pre, cue) => {return pre ? `${pre}//${cue}` : cue}, '')}// 最终处理好写入本地文件路径,去下载了toDownloadFile(fileURL, localPath)}}).catch(err => {console.log(err)})})
}
const toDownloadFile (file_url, targetPath) => {var received_bytes = 0 // 当前下载量var total_bytes = 0 // 文件总大小var req = request({method: 'GET',uri: file_url,strictSSL: false,rejectUnauthorized: false}) // 下载中命名后加:.download,提示用户未下完var out = fs.createWriteStream(targetPath + '.download')req.pipe(out)req.on('response', (data) => {// 获取文件大小total_bytes = parseInt(data.headers['content-length'])})req.on('data', (chunk) => {// 更新下载进度received_bytes += chunk.lengthshowProgress(received_bytes, total_bytes, file_url)})// 下载完成req.on('end', () => {const oldPath = targetPath + '.download'if (_win) { // 判断当前窗口实例存在// 异步改名,如果异常则e有值,抛出downloaded_rename_error,在Home.vue处理,fs.rename(oldPath, targetPath, (e) => {if (!e) {// eslint-disable-next-line camelcase_win.webContents.send('downloaded' + file_url, targetPath)} else {_win.webContents.send('downloaded_rename_error', e, targetPath)}})}})
}
const showProgress (received, total, file_url) => {var percentage = (received * 100) / totalif (_win) {// 更新下载进度给渲染进程, 这里注意加上file_url为了防止,多个文件同时下载,让渲染进程进行分辨的,只监听自己的下载进度_win.webContents.send('download-progress' + file_url, percentage)}
}
图1
之后我们将这个文件在主进程中引入即可
import { downloadFile } from '