Electron 学习指南
Electron 是一个使用 JavaScript、HTML 和 CSS 构建跨平台桌面应用程序的框架。它将 Chromium 和 Node.js 合并到一个运行时环境中,让开发者可以使用 Web 技术构建原生应用。
🚀 快速开始
创建 Electron 项目
# 创建新项目
mkdir my-electron-app
cd my-electron-app
npm init -y
# 安装 Electron
npm install electron --save-dev
# 安装开发工具
npm install electron-builder --save-dev基本项目结构
my-electron-app/
├── package.json
├── main.js # 主进程
├── preload.js # 预加载脚本
├── renderer.js # 渲染进程
├── index.html # 主窗口
└── src/
├── assets/
└── styles/📚 核心概念
主进程和渲染进程
Electron 应用由两个进程组成:
// main.js - 主进程
const { app, BrowserWindow } = require('electron');
const path = require('path');
function createWindow() {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js')
}
});
mainWindow.loadFile('index.html');
}
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});// preload.js - 预加载脚本
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
sendMessage: (message) => ipcRenderer.send('message', message),
onMessage: (callback) => ipcRenderer.on('message', callback)
});<!-- index.html - 渲染进程 -->
<!DOCTYPE html>
<html>
<head>
<title>Electron App</title>
</head>
<body>
<h1>Hello Electron!</h1>
<button id="sendBtn">Send Message</button>
<script src="renderer.js"></script>
</body>
</html>// renderer.js - 渲染进程脚本
document.getElementById('sendBtn').addEventListener('click', () => {
window.electronAPI.sendMessage('Hello from renderer!');
});
window.electronAPI.onMessage((event, message) => {
console.log('Received:', message);
});⚡ 进程间通信 (IPC)
主进程到渲染进程
// main.js
const { ipcMain, BrowserWindow } = require('electron');
ipcMain.handle('get-data', async () => {
return { message: 'Data from main process' };
});
ipcMain.on('send-to-renderer', (event, data) => {
// 发送到所有渲染进程
BrowserWindow.getAllWindows().forEach(window => {
window.webContents.send('message-from-main', data);
});
});渲染进程到主进程
// preload.js
contextBridge.exposeInMainWorld('electronAPI', {
getData: () => ipcRenderer.invoke('get-data'),
sendToMain: (data) => ipcRenderer.send('send-to-main', data),
onMessageFromMain: (callback) => ipcRenderer.on('message-from-main', callback)
});// renderer.js
// 调用主进程方法
window.electronAPI.getData().then(data => {
console.log(data);
});
// 发送消息到主进程
window.electronAPI.sendToMain('Hello from renderer');
// 监听主进程消息
window.electronAPI.onMessageFromMain((event, data) => {
console.log('From main:', data);
});🎯 窗口管理
创建不同类型的窗口
// main.js
const { BrowserWindow, BrowserView } = require('electron');
function createMainWindow() {
const mainWindow = new BrowserWindow({
width: 1200,
height: 800,
show: false, // 先隐藏,加载完成后再显示
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js')
}
});
mainWindow.loadFile('index.html');
mainWindow.once('ready-to-show', () => {
mainWindow.show();
});
}
function createModalWindow(parent) {
const modal = new BrowserWindow({
width: 600,
height: 400,
parent: parent,
modal: true,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js')
}
});
modal.loadFile('modal.html');
}窗口状态管理
// main.js
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({
width: 1200,
height: 800,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js')
}
});
// 保存窗口状态
mainWindow.on('close', () => {
const bounds = mainWindow.getBounds();
// 保存到配置文件
saveWindowState(bounds);
});
// 恢复窗口状态
const savedBounds = loadWindowState();
if (savedBounds) {
mainWindow.setBounds(savedBounds);
}
}🔧 应用生命周期
应用事件处理
// main.js
const { app } = require('electron');
// 应用准备就绪
app.whenReady().then(() => {
createWindow();
// macOS 应用激活
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
// 所有窗口关闭
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
// 应用即将退出
app.on('before-quit', () => {
// 保存数据
saveApplicationData();
});
// 应用退出
app.on('quit', () => {
// 清理资源
cleanup();
});📦 原生功能集成
系统托盘
// main.js
const { Tray, Menu } = require('electron');
const path = require('path');
let tray;
function createTray() {
tray = new Tray(path.join(__dirname, 'assets/icon.png'));
const contextMenu = Menu.buildFromTemplate([
{ label: '显示应用', click: () => mainWindow.show() },
{ label: '隐藏应用', click: () => mainWindow.hide() },
{ type: 'separator' },
{ label: '退出', click: () => app.quit() }
]);
tray.setToolTip('我的 Electron 应用');
tray.setContextMenu(contextMenu);
tray.on('click', () => {
mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show();
});
}文件系统操作
// main.js
const { ipcMain, dialog } = require('electron');
const fs = require('fs').promises;
ipcMain.handle('open-file', async () => {
const result = await dialog.showOpenDialog({
properties: ['openFile'],
filters: [
{ name: '文本文件', extensions: ['txt'] },
{ name: '所有文件', extensions: ['*'] }
]
});
if (!result.canceled) {
const filePath = result.filePaths[0];
const content = await fs.readFile(filePath, 'utf8');
return { filePath, content };
}
});
ipcMain.handle('save-file', async (event, content) => {
const result = await dialog.showSaveDialog({
filters: [
{ name: '文本文件', extensions: ['txt'] }
]
});
if (!result.canceled) {
await fs.writeFile(result.filePath, content);
return result.filePath;
}
});系统通知
// main.js
const { Notification } = require('electron');
function showNotification(title, body) {
new Notification({
title: title,
body: body,
icon: path.join(__dirname, 'assets/icon.png')
}).show();
}
ipcMain.handle('show-notification', (event, title, body) => {
showNotification(title, body);
});🛠️ 开发工具
开发者工具
// main.js
function createWindow() {
const mainWindow = new BrowserWindow({
// ... 其他配置
});
// 开发环境打开开发者工具
if (process.env.NODE_ENV === 'development') {
mainWindow.webContents.openDevTools();
}
}热重载
// main.js
if (process.env.NODE_ENV === 'development') {
require('electron-reload')(__dirname, {
electron: path.join(__dirname, 'node_modules', '.bin', 'electron')
});
}📦 打包和分发
使用 electron-builder
// package.json
{
"name": "my-electron-app",
"version": "1.0.0",
"main": "main.js",
"scripts": {
"start": "electron .",
"build": "electron-builder",
"build:win": "electron-builder --win",
"build:mac": "electron-builder --mac",
"build:linux": "electron-builder --linux"
},
"build": {
"appId": "com.example.myapp",
"productName": "我的应用",
"directories": {
"output": "dist"
},
"files": [
"main.js",
"preload.js",
"renderer.js",
"index.html",
"assets/**/*"
],
"win": {
"target": "nsis",
"icon": "assets/icon.ico"
},
"mac": {
"target": "dmg",
"icon": "assets/icon.icns"
},
"linux": {
"target": "AppImage",
"icon": "assets/icon.png"
}
}
}自动更新
// main.js
const { autoUpdater } = require('electron-updater');
function setupAutoUpdater() {
autoUpdater.checkForUpdatesAndNotify();
autoUpdater.on('update-available', () => {
console.log('更新可用');
});
autoUpdater.on('update-downloaded', () => {
console.log('更新已下载');
});
autoUpdater.on('error', (err) => {
console.error('更新错误:', err);
});
}🔒 安全最佳实践
安全配置
// main.js
function createWindow() {
const mainWindow = new BrowserWindow({
webPreferences: {
nodeIntegration: false, // 禁用 Node.js 集成
contextIsolation: true, // 启用上下文隔离
enableRemoteModule: false, // 禁用远程模块
preload: path.join(__dirname, 'preload.js')
}
});
}CSP 配置
<!-- index.html -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self' 'unsafe-inline';">📖 学习资源
官方文档
实用工具和库
- electron-builder: 应用打包工具
- electron-updater: 自动更新
- electron-store: 数据持久化
- electron-log: 日志记录
- electron-devtools-installer: 开发者工具安装
🔍 调试工具
- Electron DevTools: 内置开发者工具
- Spectron: Electron 应用测试框架
- electron-debug: 调试工具
最后更新: 2024年
最近更新:12/9/2025, 2:17:54 AM