0%

使用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,然后放进Electron的全局缓存目录。此时就可以让Electron通过缓存快速地完成安装。以macOS为例:

1
2
3
4
cd ~/Library/Caches/electron/
mkdir httpsgithub.comelectronelectronreleasesdownloadv7.1.5electron-v7.1.5-darwin-x64.zip
cd httpsgithub.comelectronelectronreleasesdownloadv7.1.5electron-v7.1.5-darwin-x64.zip
wget https://npm.taobao.org/mirrors/electron/7.1.5/electron-v7.1.5-darwin-x64.zip

将7.1.5换成你要下载的版本即可。

开始构建

一个Electron应用应包含以下内容:

main.js

当你启动Electron程序时,这是最先被执行的脚本。在main.js中可以创建窗口对象以构建图形界面。一个典型的main.js如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const { app, BrowserWindow } = require('electron');
const path = require('path');
const url = require('url');
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
});
mainWindow.loadFile('index.html');
mainWindow.on('closed', () => {
mainWindow = null;
});
}
app.on('ready', createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
})
app.on('activate', () => {
if (mainWindow === null) {
createWindow();
}
})

mainWindow即为BrowserWindow窗口对象。mainWindow有很多参数可以设置,例如,可以将widthheight替换为

1
2
width: electron.screen.getPrimaryDisplay().workAreaSize.width,
height: electron.screen.getPrimaryDisplay().workAreaSize.height

来实现全屏。在创建了窗口对象后,可以使用

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()方法来加载页面内容。loadFileindex.html也可以替换为任何自定义页面。
在创建窗口后,index.html会在Electron创建的Chromium环境下加载,接下来的工作就是进行前端设计,来构建桌面应用的页面。
在这个index.html中,你可以使用<script>标签来加载JavaScript代码,就像平常的HTML页面一样。
前面main.js中有这样一串代码:

1
2
3
webPreferences: {
nodeIntegration: true
}

在设定nodeIntegration: true之后,这里的JS不仅可以访问DOM,还能使用Node.js所有的API。能前能后,想怎么玩都行。你甚至可以使用jQuery,react.jsvue.js等框架。不过需要注意的是,如果使用jQuery,需要在页面中加这样一个<script>标签:

1
2
3
<script>
if (typeof module === "object") {window.jQuery = window.$ = module.exports}
</script>

否则由于module的冲突,jQuery无法正确加载。

如果你需要更多的页面,可以创建HTML文件并使用new BrowserWindow()加载这些页面。

dialog.showMessage()方法

还要注意的是,alert()会导致渲染进程阻塞(在全屏状态下使用会有严重问题),应该使用

1
2
const { dialog } = require("electron").remote;
dialog.showMessageBox({message : msg});

像这样调用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
2
3
4
const { ipcRenderer } = require("electron");
ipcRenderer.on(channel, (event, message) => {
console.log(messgae);
});

监听消息即可。

禁止拖拽文件

在旧版的Electron中,将一个HTML文件拖拽进页面中,会导致页面跳转。这一行为有些不太友好(因为Electron没有浏览器的返回键),需要通过设置addEventListener来禁用掉这一行为。不过这也被官方注意到,并且修复了:
https://github.com/electron/electron/pull/12655
现在应该不会遇到由于拖拽造成的问题了。

打包

在设计完成后,使用命令npm start即可运行。如果是全局安装的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 文档

🍭支持一根棒棒糖!