应用
Dialog与文件选择
显示系统对话框, 提供了消息提示、消息提示操作以及选择文件、保存文件等操作.
消息提示 dialog.showMessageBoxSync
消息提示
1 | // @@code-renderer: runner |
消息提示与确认
1 | // @@code-renderer: runner |
API说明
dialog.showMessageBoxSync(browserWindow, options)
显示一个消息框,它将阻止进程,直到消息框被关闭。返回值为点击的按钮的索引。
参数:
browserWindow
可以指定一个父窗口,作为模态窗口附加到该窗口。
options
type
: String (可选) - “none” | “info” | “error” | “question” 不同的type提示的图标不同;title
: String (可选) - message box 的标题,一些平台不显示,建议使用message和detail;message
: String - message box 的内容.detail
: String (可选) - 额外信息buttons
String[] - 字符串按钮数组,按钮按索引从右往左排序,如果未指定默认有一个”OK”的按钮。defaultId
: Integer (可选) - 默认高亮的按钮下标,回车的时候自动选中该项cancelId
: Integer (可选) 按esc默认点击索引按钮
返回值类型:
number
: 所点击的按钮的索引
dialog.showMessageBox(browserWindow, options)
与dialog.showMessageBoxSync类似,不同点在于:
- 这是一个异步方法,返回值为Promise类型;
- 显示的对话框可以指定一个复选框,返回值中也增加了对应的字段;
下面是带复选框的示例:
1 | // @@code-renderer: runner |
选择文件和文件夹
选择文件实例
1 | // @@code-renderer: runner |
API说明
dialog.showOpenDialogSync(browserWindow,options)
参数:
options
defaultPath
String (可选) - 设置对话框默认打开哪个路径,需要设置一个有效路径否则将不生效。buttonLabel
String (可选) - 确认按钮的文案, 当为空时, 将使用默认标签filters
默认所有文件类型都可以选择,设置后,只能选择允许的文件类型properties
String[] (可选)openFile
- 允许选择文件openDirectory
- 允许选择文件夹multiSelections
- 允许多选。showHiddenFiles
- 显示对话框中的隐藏文件
message
String (可选) - mac文件选择器的title
tips: 尝试修改options中的参数来查看效果;
返回值类型:
String[] | undefined
- 用户选择的文件或文件夹路径;如果取消对话框,则返回undefined
保存文件
实例
1 | // @@code-renderer: runner |
API说明
dialog.showSaveDialogSync(browserWindow,options)
参数:
options
defaultPath
String (可选) - 设置对话框默认打开哪个路径,需要设置一个有效路径否则将不生效。buttonLabel
String (可选) - 确认按钮的文案, 当为空时, 将使用默认标签filters
默认所有文件类型都可以选择,设置后,只能选择允许的文件类型properties
String[] (可选)openFile
- 允许选择文件openDirectory
- 允许选择文件夹multiSelections
- 允许多选。showHiddenFiles
- 显示对话框中的隐藏文件
message
String (可选) - mac文件选择器的title
返回值类型:
String[] | undefined
- 用户选择的文件或文件夹路径;如果取消对话框,则返回undefined;
完整API解释参考文档
不同场景表现
选择了一个存在的文件
提示”文件夹中已有相同名称的文件或文件夹。替换它将覆盖其当前内容。“,点击确认后返回该文件地址
选择了一个不存在的文件
返回该不存在的文件地址
错误信息弹窗
下载管理器
下载管理器
点击“试一试”按钮体验一下。
1 | // @@code-renderer: runner |
文件下载是我们开发中比较常见的业务需求,比如:导出 excel。
web 应用文件下载存在一些局限性,通常是让后端将响应的头信息改成 Content-Disposition: attachment; filename=xxx.pdf
,触发浏览器的下载行为。
在 electron 中的下载行为,都会触发 session 的 will-download 事件。在该事件里面可以获取到 downloadItem 对象,通过 downloadItem 对象实现一个简单的文件下载管理器:
如何触发下载
由于 electron 是基于 chromium 实现的,通过调用 webContents 的 downloadURL 方法,相当于调用了 chromium 底层实现的下载,会忽略响应头信息,触发 will-download 事件。
1 | // 触发下载 |
下载流程图
功能设计
在上面的效果图中,实现的简单文件下载管理器功能包含:
- 设置保存路径
- 暂停/恢复和取消
- 下载进度
- 下载速度
- 下载完成
- 打开文件和打开文件所在位置
- 文件图标
- 下载记录
设置保存路径
如果没有设置保存路径,electron 会自动弹出系统的保存对话框。不想使用系统的保存对话框,可以使用 setSavePath 方法,当有重名文件时,会直接覆盖下载。
1 | item.setSavePath(path) |
为了更好的用户体验,可以让用户自己选择保存位置操作。当点击位置输入框时,渲染进程通过 ipc 与主进程通信,打开系统文件选择对话框。
主进程实现代码:
1 | /** |
渲染进程代码:
1 | const path = await ipcRenderer.invoke('openFileDialog', 'PATH') |
暂停/恢复和取消
拿到 downloadItem 后,暂停、恢复和取消分别调用 pause
、resume
和 cancel
方法。当我们要删除列表中正在下载的项,需要先调用 cancel 方法取消下载。
下载进度
在 downloadItem 中监听 updated 事件,可以实时获取到已下载的字节数据,来计算下载进度和每秒下载的速度。
1 | // 计算下载进度 |
在下载的时候,想在 Mac 系统的程序坞和 Windows 系统的任务栏展示下载信息,比如:
- 下载数:通过 app 的 badgeCount 属性设置,当为 0 时,不会显示。也可以通过 dock 的 setBadge 方法设置,该方法支持的是字符串,如果不要显示,需要设置为 ‘’。
- 下载进度:通过窗口的 setProgressBar 方法设置。
由于 Mac 和 Windows 系统差异,下载数仅在 Mac 系统中生效。加上 process.platform === ‘darwin’ 条件,避免在非 Mac、Linux 系统下出现异常错误。
下载进度(Windows 系统任务栏、Mac 系统程序坞)显示效果:
1 | // mac 程序坞显示下载数: |
下载速度
由于 downloadItem 没有直接为我们提供方法或属性获取下载速度,需要自己实现。
思路:在 updated 事件里通过 getReceivedBytes 方法拿到本次下载的字节数据减去上一次下载的字节数据。
1 | // 记录上一次下载的字节数据 |
需要注意的是,updated 事件执行的时间约 500ms 一次。
下载完成
当一个文件下载完成、中断或者被取消,需要通知渲染进程修改状态,通过监听 downloadItem 的 done 事件。
1 | item.on('done', (e, state) => { |
打开文件和打开文件所在位置
使用 electron 的 shell 模块来实现打开文件(openPath)和打开文件所在位置(showItemInFolder)。
由于 openPath 方法支持返回值
Promise<string>
,当不支持打开的文件,系统会有相应的提示,而 showItemInFolder 方法返回值是void
。如果需要更好的用户体验,可使用 nodejs 的 fs 模块,先检查文件是否存在。
1 | import fs from 'fs' |
文件图标
很方便的是使用 app 模块的 getFileIcon 方法来获取系统关联的文件图标,返回的是 Promise<NativeImage>
类型,我们可以用 toDataURL 方法转换成 base64,不需要我们去处理不同文件类型显示不同的图标。
1 | const getFileIcon = async (path: string) => { |
下载记录
随着下载的历史数据越来越多,使用 electron-store 将下载记录保存在本地。
协议
协议自动唤起应用与自定义协议
协议: 从网页端唤起Electron应用
协议唤起示例:
什么是协议
electron注册的协议, electron会将协议注册到系统的协议列表中,它是系统层级的API,只能在当前系统下使用, 其他未注册协议的电脑不能识别。
Electron的app模块提供了一些处理协议的方法, 这些方法允许您设置协议和取消协议, 来让你的应用成为默认的应用程序。
协议的作用
注册一个协议到系统协议中, 当通过其他应用/浏览器网页端**打开新协议的链接时,浏览器会检测该协议有没有在系统协议中, 如果该协议注册过,然后唤起协议的默认处理程序(我们的应用)**。
注册协议: app.setAsDefaultProtocolClient
协议需要在ready事件后注册,具体代码如下.
1 | // @@code-renderer: runner |
使用协议
使用方式: 在浏览器地址栏输入注册好的协议,即可唤起应用。
协议唤起的链接格式: 自协议名称://参数
比如上文注册: electron-playground-code
协议,触发时会默认带上://
。
在使用的时候, 需要在浏览器地址栏输入:
1 | electron-playground-code://1234 // 1234是参数 可根据业务自行修改 |
1.6 注册协议并通过浏览器唤起后台应用的gif示例:
监听应用程序被唤起
应用程序唤起,mac系统会触发open-url事件,window系统会触发second-instance事件。
1 | // @@code-renderer: runner |
唤起应用执行回调示例
应用场景
单纯唤醒应用
只需注册协议,系统会自动打开应用。
表现:如果应用未打开将打开应用,如果应用已经打开应用将会激活应用窗口。根据协议链接的参数进行各种操作
如上面的弹窗演示, 在监听协议链接打开的时候,可以获取完整的协议链接。
我们可以根据协议链接来进行各种业务操作。
比如跳转指定链接地址,比如判断是否登录再进行跳转,比如下载指定文件等。
一些其他API
app.removeAsDefaultProtocolClient(protocol) 删除注册的协议, 返回是否成功删除的Boolean
Mac: app.isDefaultProtocolClient(protocol) 当前程序是否为协议的处理程序。
app.getApplicationNameForProtocol(url) 获取该协议链接的应用处理程序
参数说明:
protocol 不包含:// 注册的协议名。
url 包含://
1 | // @@code-renderer: runner |
自定义协议
注册自定义协议,拦截基于现有协议的请求,根据注册的自定义协议类型返回对应类型的数据。
在该项目中的代码地址: electron-playground/app/protocol, 可以运行项目调试一下看看效果。
protocol.registerSchemesAsPrivileged
将协议注册成标准的scheme, 方便后续调用。
注意: 它必须在ready事件加载之前调用,并且只能调用一次。
1 | protocol.registerSchemesAsPrivileged([ |
protocol.registerFileProtocol
拦截自定义协议的请求回调,重新处理后再请求路径。
示例
1 | protocol.registerFileProtocol( |
PS: 在文档上提供了不同种类的加载API,这里只演示其中的一种。
使用方式
在html中使用自定义协议请求文件,即可自动拦截。
1 | <img src={"myscheme://page/protocol/wakeUp.jpg"} alt="wakeUp"/> |
protocol其他API
托盘
创建托盘
- 引入Tray类
- 获取图标地址
- 实例化tray并传入图标地址
代码如下:
1 | // @@code-renderer: block |
一个系统托盘就会被创建出来。很简单对不对,但是这个图标还没有任何功能,接下来我们为图标添加一些属性和事件。
设置托盘属性
常用属性和事件
为tray实例设置一些属性和事件,包括上下文菜单、鼠标移入文字。详细文档点击这里。
这里我们为tray设置灵活图标,让它可以根据系统主题显示不同的图标;再设置一个鼠标移入图标的时候会显示的提示文字,最后为它设置上下文菜单,让它可以具备一些功能。
先看下效果图:
附上代码:
1 | // @@code-renderer: runner |
你可以修改提示或者菜单来试一下。这里可以设置多个托盘,实际应用中要注意设置单例锁。
我们设置了托盘根据系统主题显示不同的图标,但是系统主题是动态的,又该怎么做呢,请看:
1 | // @@code-renderer: block |
添加一个主题监听事件就好了。把这段代码复制到上面执行看下效果吧。
显示未读消息数(macOS)
在macOS系统下,可以采用setTitle(String)设置未读消息数。PS:windows下无效果。
1 | // @@code-renderer: block |
效果是这样的:
你也可以复制到上面代码编辑器中然后点击执行看下效果。
有未读消息时图标闪动(windows)
在windows系统下,可通过setImage设置正常图标与空图标切换达到闪动效果。在mac系统下空图标不占用图标空间,所以需要设置透明图标。
你可以在下面示例中用darkIcon代替nativeImage.createEmpty()然后执行看一下效果。
如何判断操作系统平台,点击这里
windows下效果:
附代码:
1 | // @@code-renderer: runner |
双击托盘显示隐藏界面(windows)
windows下效果:
附代码:
1 | // @@code-renderer: runner |
注:此效果在windows上良好,在mac下会有兼容性问题,双击事件可能失效,实际使用过程中要注意。
菜单
简介
菜单主要分为应用程序菜单、上下文菜单,在tray和dock中也有用到菜单,本节主要介绍前两种。文档地址
以下案例如有操作到应用程序菜单,可点击右下角撤回恢复正常菜单。
应用程序菜单
mac和windows都在左上角,但是一个在屏幕左上角一个在应用程序视图左上角。
mac是这样的:
windows长这样:
如果windows下没有显示菜单,在当前窗口按alt键即会出现。
创建菜单
创建应用程序菜单
接下来我们创建应用程序菜单。如下步骤:
- 引入Menu类
- 定义一个菜单模板
- 调用Menu类的
buildFromTemplate
方法,该方法会根据传入的模板创建对应的菜单 - 调用Menu类的
setApplicationMenu
方法
此四步即可创建应用程序菜单,先来看下效果图。
附上代码:
1 | // @@code-renderer: runner |
点击执行后看左上菜单效果。
创建上下文菜单
即创建右键点击菜单,前三步与创建应用程序菜单相同,最后一步需监听窗口context-menu
事件展示菜单选项。
监听事件context-menu文档
先上效果图。
附上代码:
1 | // @@code-renderer: runner |
可能你已经发现,这个例子的代码比上个例子少,实现的菜单却更多,而且这个role
又是干嘛的呢,别急,往下看。
设置菜单属性
上节说到,这个role
是干嘛的呢?
其实创建菜单行为有两种方式,一种是自定义,即1.1中实现方式,另外一种是预定义即role
。
role是MenuItem的属性,是electron的预定义行为。文档说:最好给任何一个菜单指定 role去匹配一个标准角色, 而不是尝试在 click 函数中手动实现该行为。 内置的 role 行为将提供最佳的原生体验。使用 role 时, label 和 accelerator 值是可选的, 并为每个平台,将默认为适当值。
这就是说,你只要设置好role属性,那么这个菜单的文案、快捷键、事件行为都已内部实现,而且比自定义的行为体验更好。
// @@code-renderer: runner
// @@code-props: {height: '500px', hideRight: true}
const { Menu, BrowserWindow } = require('electron')
const templateCustom = [
{
label: 'app', // macOS下第一个标签是应用程序名字,此处设置无效
submenu: [
{ label: 'quit', role: 'quit' },
{label: '关于', role: 'about', accelerator: 'CommandOrControl + shift + H' }
]
},
{
label: '编辑',
submenu: [
{role: 'editMenu'},
{type: 'separator'},
{label: '自定义', click: () => {
const win = new BrowserWindow()
win.loadURL('https://electronjs.org')
} }
]
}
]
const customMenu = Menu.buildFromTemplate(templateCustom)
Menu.setApplicationMenu(customMenu)
line8的accelerator
相信你看一眼就知道是设置快捷键的属性,你也可以自己更改快捷键点击执行试一下。