前言
什么是 Electron
Electron 是一个使用 JavaScript、HTML 和 CSS 构建跨平台桌面应用程序的框架。
它基于 Node.js 和 Chromium,让你可以使用前端技术开发桌面应用。
主进程和渲染进程
- 主进程:运行 package.json 中 main 脚本的进程,负责创建和管理应用窗口
- 渲染进程:每个 Electron 窗口运行一个独立的渲染进程,显示网页内容
快速体验
将 html
页面封装成桌面端应用,可以在 Github 拉取 演示项目 理解原理
项目运行
拉取项目&下载依赖&运行
PowerShell
# Clone this repository
git clone https://github.com/electron/minimal-repro
# Go into the repository
cd minimal-repro
# Install dependencies
npm install
# Run the app
npm start
main.js 代码部分
JavaScript
// 引入控制应用生命周期和创建原生浏览器窗口的模块
const { app, BrowserWindow } = require('electron')
const path = require('node:path')
function createWindow () {
// 创建浏览器窗口
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
icon:'./build/icon.ico',
// frame: false, // 设置为无边框窗口
webPreferences: {
preload: path.join(__dirname, 'preload.js') // 预加载脚本
}
})
// 移除菜单栏
mainWindow.setMenu(null)
// 加载应用的 index.html 文件
mainWindow.loadFile('index.html')
// 打开开发者工具(调试用,默认注释掉)
// mainWindow.webContents.openDevTools()
}
// 当Electron完成初始化并准备创建浏览器窗口时调用此方法
// 某些API只能在此事件发生后使用
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
// 在macOS上,当点击dock图标且没有其他窗口打开时,
// 通常会重新创建一个窗口
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// 当所有窗口都关闭时退出应用,除了macOS
// 在macOS上,应用及其菜单栏通常会保持活动状态,
// 直到用户使用Cmd + Q显式退出
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
// 你可以在这个文件中添加应用特定的主进程代码
// 也可以将它们放在单独的文件中并在这里引入
preload.js 预加载脚本
JavaScript
/**
*预加载脚本在加载`index.html`之前运行
*在渲染器中。它可以访问web API以及
*Electron的渲染器处理模块和一些polyfill
*Node.js函数。 https://www.electronjs.org/docs/latest/tutorial/sandbox
*/
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])
}
})
效果展示

项目打包
使用 electron-builder 打包应用,下载依赖
PowerShell
npm install electron-builder --save-dev
# 或
yarn add electron-builder --dev
配置 package.json(在 package.json
中添加 build
配置,例如)
JSON
{
"name": "your-app-name",
"version": "1.0.0",
"main": "main.js",
"scripts": {
"start": "electron .",
"pack": "electron-builder --dir", // 生成未打包的应用程序(测试用)
"dist": "electron-builder" // 生成安装包
},
"build": {
"appId": "com.example.yourapp",
"productName": "YourApp",
"win": {
"target": "nsis", // Windows 安装包格式(也可以是 portable、zip 等)
"icon": "build/icon.ico" // 应用图标
},
"mac": {
"target": "dmg", // macOS 安装包格式
"icon": "build/icon.icns" // 应用图标
},
"linux": {
"target": "AppImage", // Linux 安装包格式
"icon": "build/icon.png" // 应用图标
}
},
"devDependencies": {
"electron": "^latest",
"electron-builder": "^latest"
}
}
关键配置说明
appId
:应用唯一标识(如com.company.appname
)。productName
:应用名称(显示在安装界面)。win
/mac
/linux
:不同平台的打包配置。target
:打包格式(如 Windows 的nsis
、macOS 的dmg
、Linux 的AppImage
)。icon
:应用图标路径(需提前准备.ico
、.icns
或.png
文件)
准备应用图标(你可以使用在线工具(如 icoconvert)生成这些图标,并放在 build/
目录下)
项目目录
your-project/
├── build/
│ ├── icon.ico # Windows 图标
│ ├── icon.icns # macOS 图标
│ └── icon.png # Linux 图标
├── main.js # Electron 主进程文件
├── package.json
└── ...
运行打包命令(需要以管理员的方式打开终端才可以打包资源文件)
PowerShell
npm run dist
# 或
yarn dist
打包完成后,生成的安装文件会存放在 dist/
目录:
- Windows:
your-app-setup.exe
(NSIS 安装包)或your-app-portable.exe
(绿色版) - macOS:
your-app.dmg
(安装镜像)或your-app.app
(可直接运行) - Linux:
your-app.AppImage
(可执行文件)
可选:代码签名(发布正式版)
如果要发布到应用商店或防止安全警告,需要对应用进行签名
- Windows:使用
signtool
或购买代码签名证书(如 DigiCert)。 - macOS:需要 Apple 开发者账号,使用
codesign
。 - Linux:通常不需要签名。
在package.json
的build
配置中添加签名信息
PowerShell
"win": {
"target": "nsis",
"signingHashAlgorithms": ["sha256"],
"certificateFile": "path/to/cert.pfx",
"certificatePassword": "your-password"
},
"mac": {
"target": "dmg",
"identity": "Developer ID Application: Your Name (TEAMID)"
}
效果展示

将 html 页面封装成桌面端
从头开始
从零开始创建一个基础的 electron 的项目。构建项目结构、开发纯净的 electron 项目
前置配置
确认依赖是否安装
PowerShell
node -v # 检查版本,建议 >=16.x
npm -v # 检查npm版本
创建项目目录
PowerShell
mkdir my-electron-app
cd my-electron-app
项目初始化 & 安装依赖
PowerShell
npm init -y
npm install electron --save-dev
创建基本文件结构
PowerShell
my-electron-app/
├── package.json
├── main.js # 主进程文件
├── preload.js # 预加载脚本
└── index.html # 渲染进程页面
配置文件
主进程 (main.js)
main.js
const { app, BrowserWindow } = require('electron')
const path = require('path')
let mainWindow
function createWindow() {
// 创建浏览器窗口
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js') // 预加载脚本
}
})
// 加载应用页面
mainWindow.loadFile('index.html')
// 开发模式下自动打开开发者工具
if (process.env.NODE_ENV === 'development') {
mainWindow.webContents.openDevTools()
}
// 窗口关闭时触发
mainWindow.on('closed', () => {
mainWindow = null
})
}
// Electron 初始化完成后调用
app.whenReady().then(createWindow)
// 所有窗口关闭时退出应用 (macOS 除外)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
// macOS 点击 dock 图标重新创建窗口
app.on('activate', () => {
if (mainWindow === null) {
createWindow()
}
})
预加载脚本 (preload.js)
preload.js
const { contextBridge } = require('electron')
// 安全地暴露 API 给渲染进程
contextBridge.exposeInMainWorld('electronAPI', {
doThing: () => console.log('暴露给渲染进程的方法')
})
渲染进程页面 (index.html)
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Electron App</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
margin-top: 50px;
}
</style>
</head>
<body>
<h1>Hello Electron!</h1>
<p>Welcome to your Electron application.</p>
<script>
// 使用预加载脚本暴露的 API
window.electronAPI.doThing()
</script>
</body>
</html>
修改 package.json
JSON
{
"name": "electron",
"version": "1.0.0",
"main": "main.js",
"scripts": {
"start": "electron .",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"devDependencies": {
"electron": "^37.1.0" // 按当前版本替换
}
}
运行项目
PowerShell
npm start
打包应用 (可选:安装打包工具) 或者可以参考 上文打包方案
PowerShell
npm install electron-packager --save-dev
添加打包脚本到 package.json
package.json
"scripts": {
"package": "electron-packager . --out=dist --platform=win32 --arch=x64 --overwrite"
}
运行打包
PowerShell
npm run package
效果展示

进程通信
若需要 html
界面和 electron
形成一个通信的效果,例如 html
中按钮退出使其界面关闭。可使用 ipcMain
方案
简单案例
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="close">取消焦点</button>
<button id="use">获取焦点</button>
<button id="btn">退出</button>
<script>
document.querySelector('#btn').addEventListener('click', () => {
window.electronAPI.quitApp()
})
document.querySelector('#close').addEventListener('click', () => {
window.electronAPI.colseFocus()
})
document.querySelector('#use').addEventListener('click', () => {
window.electronAPI.useFocus()
})
</script>
</body>
</html>
preload.js
const { contextBridge } = require('electron')
const { ipcRenderer } = require('electron')
// 安全地暴露 API 给渲染进程
contextBridge.exposeInMainWorld('electronAPI', {
quitApp: () => ipcRenderer.send('quit-app'),
colseFocus: () => ipcRenderer.send('colse-focus'),
useFocus: () => ipcRenderer.send('use-focus')
})
main.js
const { app, BrowserWindow, ipcMain } = require('electron')
const path = require('path')
let mainWindow
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
alwaysOnTop: true,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true, // 推荐开启
enableRemoteModule: false // 禁用 remote 模块
}
})
mainWindow.setMenu(null)
mainWindow.loadFile('index.html')
if (process.env.NODE_ENV === 'development') {
mainWindow.webContents.openDevTools()
}
mainWindow.on('closed', () => {
mainWindow = null
})
}
app.whenReady().then(createWindow)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
// 更安全的 IPC 通信处理
ipcMain.on('quit-app', () => {
app.quit()
})
ipcMain.on('colse-focus', (event) => {
const win = BrowserWindow.fromWebContents(event.sender)
win.setAlwaysOnTop(false)
if (!win) return false
win.blur()
return true
})
ipcMain.on('use-focus',(event)=>{
const win = BrowserWindow.fromWebContents(event.sender)
win.setAlwaysOnTop(true)
if (!win) return false
win.focus()
return true
})
app.on('activate', () => {
if (mainWindow === null) createWindow()
})
效果展示
