Electron 是一个使用 JavaScript、HTML 和 CSS 构建跨平台的桌面应用程序。它基于 Node.js 和 Chromium,被 Atom 编辑器和许多其他应用程序使用。
Electron 兼容 Mac、Windows 和 Linux,可以构建出三个平台的应用程序。

安装Electron

1
2
3
4
# 新建项目需要, 不新建可以忽视
npm init -y
npm install electron --save-dev
npm install electron-builder --save-dev

安装碰到长时间拉不下来的问题请换源

1
2
3
registry=https://registry.npmmirror.com
electron_mirror=https://cdn.npmmirror.com/binaries/electron/
electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/

在 npm 用户文件夹下 .npmrc 文件中添加, 或者执行以下命令基本就能看到该文件的地址并直接修改文件

1
npm config edit

以下是配置package.json 文件信息

  • extraResources 配置资源目录复制到打包目录
  • productName 打包后exe名称
  • files 程序打包进内部的文件
  • asarUnpack 主进程文件复制到资源目录,一般没用 建议删除 主进程文件
    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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    {
    "name": "exe-test",
    "version": "1.0.0",
    "description": "",
    "main": "main.js",
    "scripts": {
    "start": "electron . --inspect",
    "pack": "electron-builder --dir",
    "dist": "electron-builder"
    },
    "build": {
    "appId": "com.example.mywebapp",
    "productName": "项目网址",
    "win": {
    "target": [
    "nsis"
    ]
    },
    "extraResources": [
    {
    "from": "res",
    "to": "../res"
    }
    ],
    "nsis": {
    "oneClick": false,
    "allowToChangeInstallationDirectory": true,
    "artifactName": "项目网址.exe"
    },
    "directories": {
    "buildResources": "build-resources"
    },
    "asarUnpack": [
    "main.js",
    "preload.js"
    ],
    "files": [
    "main.js",
    "index.html",
    "preload.js",
    "renderer.js",
    "package.json",
    "node_modules/**/*",
    "assets/**/*"
    ],
    "asar": true
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
    "@electron-forge/maker-squirrel": "^7.4.0",
    "electron": "^31.3.1",
    "electron-builder": "^24.13.3",
    "electron-packager": "^17.1.2"
    }
    }

main.js

package.json 中定义的入口被 称为主进程。 在主进程中实例化 BrowserWindow 创建的
Web 页面被称为渲染进程。主进程只有一个 渲染进程可以有多个 。

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// main.js
const { app, BrowserWindow, globalShortcut, ipcMain } = require('electron')
const fs = require('fs');
const path = require('path')
let mainWindow
let shortcutRegistered = false;

function createWindow () {
// 读取配置文件, 配置文件放在同级 res 目录
const configPath = path.join("res/", 'config.json');
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
mainWindow = new BrowserWindow({
// width: 800,
// height: 600,
// 窗口全屏
fullscreen: true,
autoHideMenuBar: true, // 设置菜单栏自动隐藏
skipTaskbar: true, // 设置窗口不显示在任务栏上
webPreferences: {
//渲染进程中是否可以使用 Node.js 的全局对象
nodeIntegration: true,
//Node.js 的全局对象(如 require, module, process, global 等)将不会暴露给渲染进程中的 Web 内容, 同时可以继续使用 preload.js 文件
contextIsolation: false,
// 支配资源与网址内信息一起走 通过 ipc 调用
preload: path.join(__dirname, 'preload.js'),
},
alwaysOnTop: true, // 设置窗口始终位于顶层
})

// 加载外部网站
mainWindow.loadURL(config.url)

// 注册全局快捷键
// registerGlobalShortcuts()

mainWindow.on('closed', function () {
mainWindow = null
})
mainWindow.setMenu(null);

// 监听来自渲染进程的消息
ipcMain.on('close-app', (event) => {
app.quit(); // 退出整个应用
});
// 注册快捷键
if (!shortcutRegistered) {
// 可以 ctrl + shift + h 关闭浏览器窗口
globalShortcut.register('CommandOrControl+Shift+H', () => {
// 取消注册快捷键
globalShortcut.unregister('CommandOrControl+Shift+H');
app.quit(); // 当按下快捷键时关闭程序
});

shortcutRegistered = true;
}

function registerGlobalShortcuts() {
// 注册全局快捷键
const isRegisteredCtrlShiftI = globalShortcut.register('CommandOrControl+Shift+I', () => {
console.log('Ctrl+Shift+I is disabled');
});

const isRegisteredF12 = globalShortcut.register('F12', () => {
console.log('F12 is disabled');
});

if (!isRegisteredCtrlShiftI || !isRegisteredF12) {
console.error('Failed to register one or more global shortcuts.');
}

// 当应用关闭时,注销所有全局快捷键
app.on('before-quit', () => {
globalShortcut.unregisterAll();
});
}

app.whenReady().then(createWindow)

app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})

app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})

preload.js

preload.js 是一个特殊的脚本文件,它在渲染进程(即 Electron 的网页页面)加载之前运行,并且在渲染进程的上下文中执行。这意味着它具有访问 Node.js 模块和 Electron 远程对象的能力,同时还能访问渲染进程的 DOM API。
preload.js 的主要作用包括:

  • 暴露 Node.js 功能给渲染进程:通过在 preload.js 中使用 exposeInMainWorld 方法,开发者可以将 Node.js 的模块或 Electron 的功能安全地暴露给渲染进程的页面。这样,渲染进程就可以像使用前端库一样使用这些功能,而不需要直接操作 Electron 的远程对象。
  • 提供安全的上下文环境:preload.js 运行在一个特殊的上下文中,它与页面的普通 JavaScript 环境是隔离的。这样可以防止页面脚本直接访问 Node.js 的某些敏感功能,增强了应用的安全性。
  • 初始化全局状态或功能:在 preload.js 中,可以初始化一些全局的状态或功能,这些状态或功能可以在渲染进程中的任何页面或组件中使用。
  • 模块化管理:preload.js 可以作为模块化管理的入口,将一些通用的逻辑或工具函数预先加载到渲染进程中,以便在不同的页面或组件中复用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}

for (const type of ['chrome', 'node', 'electron']) {
replaceText(`${type}-version`, process.versions[type])
}
})

// preload.js
window.closeApp = function() {
// 发送关闭信号给主进程
require('electron').ipcRenderer.send('close-app');
}

config.json 使用资源文件

1
2
3
{
"url": "http://127.0.0.1/"
}

index.html

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<h1 id="chrome-version"></h1>
<h1 id="node-version"></h1>
<h1 id="electron-version"></h1>
</body>
</html>