危险

为之则易,不为则难

0%

Electron 基础

🦐 Electron 是一个用于构建桌面应用程序的开发框架(Chromium + Node.js + Native API)。

初始化工程

1
2
3
npm init -y

npm i electron -D # 可能小慢,耐心等待

package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"name": "ele",
"version": "1.0.0",
# 入口
"main": "main.js",
"scripts": {
"start": "electron ."
},
"keywords": [],
# 打包必须
"author": "Ifer",
# 打包必须
"license": "ISC",
"description": "Hello World",
"devDependencies": {
"electron": "^37.2.5"
}
}

创建主进程

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
29
const { app, BrowserWindow } = require("electron");

const createWindow = () => {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
autoHideMenuBar: true,
x: 0,
y: 0,
alwaysOnTop: true,
});
// TODO: 加载页面
};

app.on("ready", () => {
createWindow()
// 如果没有窗口打开则打开一个窗口(macOS)
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});

// 如何打开控制台?
// ctrl + shift + i,有时候有点慢,别着急
// 关闭所有窗口时退出应用
app.on("window-all-closed", () => {
// 非 macOS 则调用 app.quit()
if (process.platform !== "darwin") app.quit();
});

加载新页面

main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
autoHideMenuBar: true,
x: 0,
y: 0,
alwaysOnTop: true
});
// win.loadURL('https://www.baidu.com')
// 在主进程中,通过窗口打开页面
win.loadFile("./pages/index.html");
}

pages/index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<meta
http-equiv="X-Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<title>来自 Electron 渲染器的问好!</title>
</head>
<body>
Hello World
</body>
</html>

重启新窗口

1
npm i nodemon -D

package.json

1
2
3
4
5
6
{
// ...
"scripts": {
"start": "nodemon --exec electron ."
}
}

nodemon.json

1
2
3
4
5
6
7
8
9
10
{
"ignore": [
"node_modules",
"dist"
],
// 在 Terminal 输入 r 敲回车可重启
"restartable": "r",
"watch": ["*.*"],
"ext": "html,js,css"
}

预加载脚本

为了将不同类型的进程桥接在一起,我们需要使用被称为「预加载」的特殊脚本,例如需要将主进程的 API 暴漏给渲染进程。

preload.js

1
2
3
4
5
6
7
8
const { contextBridge } = require('electron')

contextBridge.exposeInMainWorld('versions', {
node: () => process.versions.node,
chrome: () => process.versions.chrome,
electron: () => process.versions.electron
// 除函数之外,我们也可以暴露变量
})

在 BrowserWindow 构造器中使用 webPreferences.preload 传入脚本的路径。

1
2
3
4
5
6
7
8
9
10
11
const win = new BrowserWindow({
width: 800,
height: 600,
autoHideMenuBar: true,
x: 0,
y: 0,
alwaysOnTop: true,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
});

pages/renderer.js

1
2
const information = document.getElementById("info");
information.innerText = `本应用正在使用 Chrome (v${versions.chrome()}), Node.js (v${versions.node()}), 和 Electron (v${versions.electron()})`;

pages/index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<meta
http-equiv="X-Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<title>来自 Electron 渲染器的问好!</title>
</head>
<body>
Hello World
<div id="info"></div>
<script src="./renderer.js"></script>
</body>
</html>

进程间通信

https://www.electronjs.org/zh/docs/latest/tutorial/ipc

渲染进程到主进程(单)

渲染进程到主进程(双)

1. 主进程中通过 ipcMain.handle() 监听事件并返回数据给预加载脚本触发的地方;
2. 预加载脚本中定义函数,通过 ipcRenderer.invoke() 触发主进程中监听的事件,拿到主进程返回的数据,并返回数据给渲染进程;
3. 渲染进程中通过调用预加载脚本中暴漏的函数拿到数据。

主进程到渲染进程

渲染进程到渲进程

https://www.electronjs.org/zh/docs/latest/tutorial/ipc#%E6%A8%A1%E5%BC%8F-3%E4%B8%BB%E8%BF%9B%E7%A8%8B%E5%88%B0%E6%B8%B2%E6%9F%93%E5%99%A8%E8%BF%9B%E7%A8%8B

项目的打包

1
npm i electron-builder -D

package.json

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
29
30
31
32
33
{
"name": "ele",
"version": "1.0.0",
"main": "main.js",
"scripts": {
"start": "nodemon --exec electron .",
"build": "electron-builder"
},
"keywords": [],
"author": "Ifer",
"license": "ISC",
"description": "Hello World",
"devDependencies": {
"electron": "^37.2.5",
"electron-builder": "^26.0.12",
"nodemon": "^3.1.4"
},
"build": {
"appId": "com.electron.ele",
"win": {
"icon": "./logo.ico", // 注意这儿至少是 256*256 的尺寸
"target": [{
"target": "nsis", // 使用 NSIS 作为安装程序格式
"arch": ["x64"] // 生成 64 位安装包
}]
},
"nsis": {
"oneClick": false, // 显示安装向导
"perMachine": true, // 为当前主机安装,而不是每个用户
"allowToChangeInstallationDirectory": true // 允许用户更改安装目录
}
}
}
1
2
# 注意管理员模式下打开命令行工具
npm run build

Electron Vite

https://cn.electron-vite.org/guide/introduction