简介
使用HTML、CSS和JavaScript构建跨平台的桌面应用程序。Electron的本质是结合了Chromium与Node.js。Electron=Chromium + Node.js + Native API
创建应用程序
1.在使用Electron进行开发之前,先安装 Node.js
2.初始化项目
(1) 配置 package.json
npm init
注意:entry point应为main.js;author 、license和 description 可为任意值,但对于应用打包是必填项
(2) 将 Electron 安装为项目的devDependencies,即仅在开发环境需要的额外依赖
npm install electron --save-dev
或者也可以使用下面的命令
npm install -g cnpm --registry=https://registry.npmmirror.com
cnpm install --save-dev electron
打包后的应用本身会包含 Electron 的二进制文件,因此不需要将 Electron 作为生产环境依赖
在package.json文件中的scripts字段下增加一条start命令
{
"name": "first",
"version": "1.0.0",
"description": "Hello",
"main": "main.js",
"scripts": {
"start": "electron .", // 告诉 Electron 在当前目录下寻找主脚本,并以开发模式运行它
"test": "echo "Error: no test specified" && exit 1"
},
"author": "abc",
"license": "ISC",
"devDependencies": {
"electron": "^31.1.0"
}
}
(3) 创建一个名为main.js的文件
console.log('Hello from Electron 👋')
(4) 添加 .gitignore 文件
建议复制一份 GitHub 的 Node.js gitignore 模板(github.com/github/giti…) 到项目的根目录,以避免将node_modules文件夹提交到版本控制系统中。
3.运行Electron应用
npm run start
此时终端会输出 Hello from Electron 👋
4.将网页装载到 BrowserWindow及管理应用的窗口生命周期
在 Electron 中,每个窗口展示一个页面,该页面可以来自本地的 HTML,也可以来自远程 URL。此处以装载本地文件为例
(1) 在项目根目录中创建index.html
<html>
<head>
<meta charset="UTF-8" />
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<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>Hello from Electron renderer!</title>
</head>
<body>
<h1>Hello from Electron renderer!</h1>
<p>👋</p>
</body>
</html>
(2) 将网页加载到Electron的BrowsetWindow及管理应用的窗口生命周期
Electron 的许多核心模块都是 Node.js 的事件触发器,遵循 Node.js 的异步事件驱动架构,如app模块。在 Electron 中,只有在 app 模块的 ready事件触发后才能创建 BrowserWindows 实例, 可以通过使用 app.whenReady()API 来监听此事件,并在其成功后调用 createWindow() 方法
Electron应用中的每个页面都在一个单独的进程中运行,我们称这些进程为渲染器renderer ,渲染进程使用与常规Web开发相同的JavaScript API和工具。Electron 目前只支持三个平台:win32(Windows), linux(Linux) 和 darwin (macOS)
在Windows和Linux上,关闭所有窗口通常会完全退出一个应用程序。为了实现这一点,需要监听 app模块的 window-all-closed 事件。如果用户不是在 macOS(darwin) 上运行程序,则调用 app.quit()
macOS 应用通常即使在没有打开任何窗口的情况下也继续运行,并且在没有窗口可用的情况下激活应用时会打开新的窗口。为了实现这一特性,监听 app 模块的 activate事件。如果没有任何浏览器窗口是打开的,则调用 createWindow()方法。因为窗口无法在 ready 事件前创建,因此在 whenReady()回调中监听activate事件来完成这个操作
// main.js
// 使用 CommonJS 语法导入 Electron 模块,app控制应用程序的事件生命周期,BrowserWindow负责创建和管理应用窗口
const { app, BrowserWindow } = require('electron/main')
// 将页面加载到新的 BrowserWindow 实例中
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
// autoHideMenuBar: true, 隐藏菜单栏
// x: 0, 窗口位置x坐标
// y: 0, 窗口位置y坐标
// alwaysOnTop: true 置顶
})
win.loadFile('index.html')
}
// 在应用准备就绪时调用函数
app.whenReady().then(() => {
createWindow()
// 如果没有窗口打开则打开一个窗口 (macOS)
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
// 关闭所有窗口时退出应用,不适用macOS (Windows & Linux)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
注意:Electron 遵循 JavaScript 传统约定,以帕斯卡命名法 (PascalCase) 命名可实例化的类 (如 BrowserWindow, Tray 和 Notification),以驼峰命名法 (camelCase) 命名不可实例化的函数、变量等 (如 app, ipcRenderer, webContents)
5.通过预加载脚本从渲染器访问Node.js
Electron 的主进程是一个拥有着完全操作系统访问权限的 Node.js 环境,除了 Electron 模块之外,也可以访问 Node.js 内置模块和所有通过 npm 安装的包。而出于安全原因,渲染进程默认跑在网页页面上,并非 Node.js里。因此为了将 Electron 的不同类型的进程桥接在一起,需要使用被称为预加载的特殊脚本
(1) 使用预加载脚本来增强渲染器
BrowserWindow 的预加载脚本运行在具有 HTML DOM 和 Node.js、Electron API 的有限子集访问权限的环境中。从 Electron 20 开始,预加载脚本默认沙盒化 ,不再拥有完整 Node.js 环境的访问权
与 Chrome 扩展的内容脚本(Content Script)类似,预加载脚本在渲染器加载网页之前注入。 如果想为渲染器添加需要特殊权限的功能,可以通过contextBridge接口定义全局对象
A. 新建preload.js。这里通过 versions这一全局变量,将 Electron 的 process.versions 对象暴露给渲染器
// preload.js
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('versions', { // 这里相当于是给window设置了属性versions
node: () => process.versions.node,
chrome: () => process.versions.chrome,
electron: () => process.versions.electron
// 除函数之外,也可以暴露变量
})
B. 为了将脚本附在渲染进程上,在 BrowserWindow 构造器中使用 webPreferences.preload传入脚本的路径
// main.js
const path = require('node:path')
//...
const createWindow = () => {
const win = new BrowserWindow({
//...
// 在现有的 BrowserWindow 构造器中将路径中的预加载脚本传入 webPreferences.preload 选项
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
win.loadFile('index.html')
}
//...
C. 新建renderer.js。此时渲染器可以全局访问versions,该变量可以通过window.versions访问,也可以使用versions访问
// renderer.js
const information = document.getElementById('info')
information.innerText = `This app is using Chrome (v${versions.chrome()}), Node.js (v${versions.node()}), and Electron (v${versions.electron()})`
D. 修改index.html,加上一个 id 属性为 info的全新元素,并且引入renderer.js 脚本
// index.html
//...
<body>
<h1>Hello from Electron renderer!</h1>
<p>👋</p>
<p id="info"></p>
<script src="./renderer.js"></script>
</body>
</html>
//...
此时项目的运行结果为:
由于主进程和渲染进程有着完全不同的分工,Electron 应用通常使用预加载脚本来设置进程间通信 (IPC) 接口以在两种进程之间传输任意信息
可以使用 Electron 的 ipcMain模块和 ipcRenderer模块来进行进程间通信。 为了从网页向主进程发送消息,可以使用 ipcMain.handle设置一个主进程处理程序(handler),然后在预处理脚本中暴露一个被称为 ipcRenderer.invoke的函数来触发该处理程序(handler)
// preload.js
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('versions', {
//...
ping: () => ipcRenderer.invoke('ping') // 在预处理脚本中设置 invoke 调用
})
// main.js
const { app, BrowserWindow, ipcMain } = require('electron/main')
//...
app.whenReady().then(() => {
ipcMain.handle('ping', () => 'pong') // 在主进程中设置 handle 监听器
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
//...
// renderer.js
//...
const func = async () => {
const response = await window.versions.ping()
console.log(response) // 打印 'pong'
}
func()
此时项目的运行结果为:
打包并分发应用程序
使用Electron Forge进行打包
1.导入项目到 Forge
将 Electron Forge 的 CLI 工具包安装到项目的 devDependencies 依赖中,然后使用现成的转化脚本将项目导入至 Electron Forge
npm install --save-dev @electron-forge/cli
npx electron-forge import
如果npx electron-forge import提示Failed to install modules: ["electron-squirrel-startup"],可以先安装electron-squirrel-startup,再npx electron-forge import
npm install --save-dev electron-squirrel-startup
或
npm install -g yarn --registry=https://registry.npmmirror.com
yarn add electron-squirrel-startup
转换脚本完成后,Forge 会将一些脚本添加到package.json 文件中
// package.json
//...
"scripts": {
"start": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make"
},
//...
2.使用 Forge 的make命令来创建可分发的应用程序
npm run make
注意:package.json的“author”和“description”在打包时是必填内容;项目的绝对路径不能出现中文
生成的out\first-win32-x64\first.exe是应用入口文件,而out\make\squirrel.windows\x64\first-1.0.0 Setup.exe是应用安装包