使用 Electron 构建桌面应用
Electron 是一个基于 Node.js,并拥有一个 Chromium「外壳」的桌面应用开发框架。你可以调用所有 Node.js 和浏览器的 API,使用 JavaScript,HTML 和 CSS 等 Web 技术创建原生程序。根据官方的宣传语:「它负责比较难搞的部分,你只需把精力放在你的应用的核心上即可。」
下面介绍如何使用 Electron 构建简单的桌面应用。你可以参照官方给出的入门程序:
1 | git clone https://github.com/electron/electron-quick-start.git |
安装
Electron 可以通过 npm install electron
来进行安装。在依赖包安装完成后,Electron 会开始下载它的「本体」—— 一个数十 MiB 大小的压缩包,包含 Electron 在不同平台下的可执行文件。这一步对于国内的开发者不太友好,因为下载的内容在 Amazon 云上,访问速度不佳;而且新版的 Electron 去除了下载进度条,导致即使出现问题,你也无法知晓卡在了哪一步。一种简单的解决方案是通过设定环境变量来使用淘宝源:
1 | ELECTRON_MIRROR="https://cdn.npm.taobao.org/dist/electron/" |
设置此环境变量后,再执行 npm install
,下载就是正常的了。
开始构建
一个 Electron 应用应包含以下内容:
main.js
当你启动 Electron 程序时,这是最先被执行的脚本。在 main.js
中可以创建窗口对象以构建图形界面。一个典型的 main.js
如下:
1 | const { app, BrowserWindow } = require("electron"); |
mainWindow
即为 BrowserWindow
窗口对象。mainWindow
有很多参数可以设置,例如,可以将 width
和 height
替换为
1 | width: electron.screen.getPrimaryDisplay().workAreaSize.width, |
来实现全屏。在创建了窗口对象后,可以使用
1 | mainWindow.setAlwaysOnTop(true, ""); |
来使应用置顶(在 macOS 下,第二个参数将决定置顶的级别,例如,第二个参数取 "floating"
会使窗口置于大部分应用之前,但会被 KeyNote 等级别更高的应用挡住;而取 "main-menu"
则即使在演示 KeyNote 该窗口也能置于顶层)。 如果窗口设置了全屏置顶,就需要配合以下代码使用:
1 | mainWindow.setIgnoreMouseEvents(true); |
这样可以使窗口忽略鼠标事件,否则就不能正常操作其他窗口了。process.platform !== "darwin"
的作用是,在 macOS 上,关闭所有窗口并不意味着退出程序 —— 你可以点击 Dock 中的程序图标唤醒它(即触发 activate
事件);而在 Windows 中,关闭所有窗口的默认行为是直接退出程序。
index.html
这是窗口的 HTML 文件。在 main.js
中,使用了 mainWindow.loadFile()
方法来加载页面内容。loadFile
中 index.html
也可以替换为任何自定义页面。
在创建窗口后,index.html
会在 Electron 创建的 Chromium 环境下加载,接下来的工作就是进行前端设计,来构建桌面应用的页面。
在这个 index.html
中,你可以使用 <script>
标签来加载 JavaScript 代码,就像平常的 HTML 页面一样。
前面 main.js
中有这样一串代码:
1 | webPreferences: { |
在设定 nodeIntegration: true
之后,这里的 JS 不仅可以访问 DOM,还能使用 Node.js 所有的 API。能前能后,想怎么玩都行。你甚至可以使用 jQuery,react.js
或 vue.js
等框架。不过需要注意的是,如果使用 jQuery,最好不要像这样加载
1 | <script src="https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js"></script> |
此时由于 module
的冲突,jQuery 并没有被定义为全局变量,也无法通过 window.$
被访问和使用。
推荐的做法是通过 npm
安装 jQuery:
1 | npm install jquery |
然后在页面中用 CommonJS 模块的方式加载
1 | window.jQuery = window.$ = require("jquery"); |
如果你需要更多的页面,可以创建 HTML 文件并使用 new BrowserWindow()
加载这些页面。
dialog.showMessage()
方法
还要注意的是,alert()
会导致渲染进程阻塞(在全屏状态下使用会有严重问题),应该使用
1 | const { dialog } = require("electron").remote; |
像这样调用 dialog.showMessage()
方法显示消息,msg
参数就是消息的内容。这是异步的,对应的同步方法是 dialog.showMessageBoxSync()
。它和 alert()
一样会阻止其它代码的执行。
相关内容可以查看:
https://github.com/electron/electron/pull/17298
https://github.com/electron/electron/issues/20855
页面间通讯
此外,Electron 提供了在不同页面间进行通讯的 API,在父页面使用
1 | mainWindow.webContents.send(channel, messageContent); |
发送消息,其中 channel 是任意字符串,表示通信频道,messageContent 是消息内容。在子页面使用
1 | const { ipcRenderer } = require("electron"); |
监听消息即可。
禁止拖拽文件
在旧版的 Electron 中,将一个 HTML 文件拖拽进页面中,会导致页面跳转。这一行为有些不太友好(因为 Electron 没有浏览器的返回键),需要通过设置 addEventListener
来禁用掉这一行为。不过这也被官方注意到,并且修复了:
https://github.com/electron/electron/pull/12655
现在应该不会遇到由于拖拽造成的问题了。
打包
在设计完成后,使用命令 npx electron .
即可运行。如果是全局安装的 electron
,则执行 electron .
。
如果需要将应用打包,可以使用 electron-builder
(用 npm
安装),在 Windows 系统下就会默认打包成.exe
格式,macOS 则为.dmg
。当然,在 macOS 上打包 Windows 版本的可执行文件也不是问题,具体可以看文档。macOS 10.15 出现了一个小 bug,不过影响不大,将 electron-builder
升级到最新就能解决:
https://github.com/electron-userland/electron-builder/issues/4305#issuecomment-559138959
发挥你的想象力,便能使用 Electron 构建功能丰富的跨平台应用啦!
参考文章:
使用 electron 构建跨平台 Node.js 桌面应用经验分享
Electron API 演示
官方文档:Electron 文档