Electron桌面应用开发完全指南(2026年03月27日) Electron是GitHub开发的开源框架,允许使用Web技术(HTML、CSS、JavaScript)构建跨平台桌面应用程序。VS Code、Slack、Notion、Figma等知名应用都基于Electron构建。 核心架构 Electron架构概览 主要组件 Main Process:主进程,Node.js环境,管理应用生命周期 Renderer Process:渲染进程,Chromium环境,运行Web页面 IPC:进程间通信,主进程与渲染进程通信的桥梁 快速开始 项目初始化 基础应用结构 创建主进程 创建预加载脚本 创建渲染进程 进程间通信(IPC) 主进程处理 单向通信(Renderer → Main)
Electron是GitHub开发的开源框架,允许使用Web技术(HTML、CSS、JavaScript)构建跨平台桌面应用程序。VS Code、Slack、Notion、Figma等知名应用都基于Electron构建。
┌─────────────────────────────────────────┐ │ Main Process │ │ (Node.js环境,管理应用生命周期) │ │ - 窗口管理 │ │ - 原生菜单 │ │ - 系统托盘 │ │ - 文件系统访问 │ └──────────────┬──────────────────────────┘ │ IPC (进程间通信) ┌──────────────┴──────────────────────────┐ │ Renderer Process (多个) │ │ (Chromium渲染进程,每个窗口一个) │ │ - Web页面渲染 │ │ - 用户界面 │ │ - 前端逻辑 │ └─────────────────────────────────────────┘
# 创建项目 mkdir my-electron-app cd my-electron-app npm init -y # 安装Electron npm install electron --save-dev # 配置package.json { "name": "my-electron-app", "version": "1.0.0", "main": "main.js", "scripts": { "start": "electron ." } }
my-electron-app/ ├── main.js # 主进程入口 ├── preload.js # 预加载脚本 ├── renderer/ # 渲染进程文件 │ ├── index.html │ ├── styles.css │ └── renderer.js ├── assets/ # 资源文件 └── package.json
// main.js const { app, BrowserWindow } = require('electron'); const path = require('path'); // 保持对窗口对象的全局引用 let mainWindow; function createWindow() { mainWindow = new BrowserWindow({ width: 1200, height: 800, minWidth: 800, minHeight: 600, webPreferences: { // 启用预加载脚本 preload: path.join(__dirname, 'preload.js'), // 禁用Node.js集成(安全最佳实践) nodeIntegration: false, contextIsolation: true, // 启用上下文隔离 }, // 添加图标 icon: path.join(__dirname, 'assets/icon.png'), // 标题栏样式 titleBarStyle: 'default', // macOS可选:hiddenInset, customButtonsOnHover // 背景颜色 backgroundColor: '#ffffff', }); // 加载index.html mainWindow.loadFile('renderer/index.html'); // 开发环境打开DevTools if (process.env.NODE_ENV === 'development') { mainWindow.webContents.openDevTools(); } // 窗口关闭时触发 mainWindow.on('closed', () => { mainWindow = null; }); } // Electron初始化完成时创建窗口 app.whenReady().then(() => { createWindow(); // macOS特定:点击Dock图标重新创建窗口 app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } }); }); // 所有窗口关闭时退出应用(macOS除外) app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } });
// preload.js const { contextBridge, ipcRenderer } = require('electron'); // 向渲染进程暴露安全的API contextBridge.exposeInMainWorld('electronAPI', { // 窗口操作 minimize: () => ipcRenderer.send('window-minimize'), maximize: () => ipcRenderer.send('window-maximize'), close: () => ipcRenderer.send('window-close'), // 文件系统操作 readFile: (filePath) => ipcRenderer.invoke('read-file', filePath), writeFile: (filePath, content) => ipcRenderer.invoke('write-file', filePath, content), // 系统信息 getPlatform: () => process.platform, getVersion: () => ipcRenderer.invoke('get-app-version'), // 通知 sendNotification: (title, body) => ipcRenderer.send('show-notification', title, body), });
<!-- renderer/index.html --> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>My Electron App</title> <link rel="stylesheet" href="styles.css"> </head> <body> <div id="app"> <h1>欢迎使用Electron</h1> <p>平台: <span id="platform"></span></p> <button id="minimizeBtn">最小化</button> <button id="maximizeBtn">最大化</button> <button id="closeBtn">关闭</button> </div> <script src="renderer.js"></script> </body> </html>
// renderer/renderer.js // 使用暴露的electronAPI document.getElementById('platform').textContent = window.electronAPI.getPlatform(); // 窗口控制 document.getElementById('minimizeBtn').addEventListener('click', () => { window.electronAPI.minimize(); }); document.getElementById('maximizeBtn').addEventListener('click', () => { window.electronAPI.maximize(); }); document.getElementById('closeBtn').addEventListener('click', () => { window.electronAPI.close(); }); // 读取文件 async function loadFile() { try { const content = await window.electronAPI.readFile('/path/to/file.txt'); console.log(content); } catch (error) { console.error('读取文件失败:', error); } }
// main.js const { ipcMain, dialog } = require('electron'); const fs = require('fs').promises; // 窗口控制 ipcMain.on('window-minimize', (event) => { const win = BrowserWindow.fromWebContents(event.sender); win.minimize(); }); ipcMain.on('window-maximize', (event) => { const win = BrowserWindow.fromWebContents(event.sender); if (win.isMaximized()) { win.unmaximize(); } else { win.maximize(); } }); ipcMain.on('window-close', (event) => { const win = BrowserWindow.fromWebContents(event.sender); win.close(); }); // 文件系统操作(双向通信) ipcMain.handle('read-file', async (event, filePath) => { try { const content = await fs.readFile(filePath, 'utf-8'); return content; } catch (error) { throw error; } }); ipcMain.handle('write-file', async (event, filePath, content) => { try { await fs.writeFile(filePath, content, 'utf-8'); return { success: true }; } catch (error) { throw error; } }); // 应用版本信息 ipcMain.handle('get-app-version', () => { return app.getVersion(); }); // 显示通知 ipcMain.on('show-notification', (event, title, body) => { new Notification({ title, body }).show(); });
// 渲染进程发送 window.electronAPI.sendMessage('Hello from renderer'); // 主进程接收 ipcMain.on('message', (event, message) => { console.log('收到消息:', message); });
// 渲染进程调用 const result = await window.electronAPI.someAsyncMethod(); console.log('返回结果:', result); // 主进程处理 ipcMain.handle('some-async-method', async (event, ...args) => { // 执行异步操作 const result = await performAsyncOperation(); return result; });
// 主进程发送 mainWindow.webContents.send('update-available', { version: '2.0.0' }); // 渲染进程接收(需要在preload.js中设置监听器) contextBridge.exposeInMainWorld('electronAPI', { onUpdateAvailable: (callback) => ipcRenderer.on('update-available', callback), }); // renderer.js使用 window.electronAPI.onUpdateAvailable((event, info) => { console.log('新版本可用:', info.version); });
// main.js let mainWindow; let preferencesWindow; function createMainWindow() { mainWindow = new BrowserWindow({ width: 1200, height: 800, webPreferences: { preload: path.join(__dirname, 'preload.js'), }, }); mainWindow.loadFile('renderer/index.html'); } function createPreferencesWindow() { if (preferencesWindow) { preferencesWindow.focus(); return; } preferencesWindow = new BrowserWindow({ width: 600, height: 400, parent: mainWindow, // 设置父窗口 modal: true, // 模态窗口 webPreferences: { preload: path.join(__dirname, 'preload.js'), }, }); preferencesWindow.loadFile('renderer/preferences.html'); preferencesWindow.on('closed', () => { preferencesWindow = null; }); } // 从渲染进程打开新窗口 ipcMain.on('open-preferences', () => { createPreferencesWindow(); });
const Store = require('electron-store'); const store = new Store(); function createWindow() { // 获取保存的窗口状态 const windowState = store.get('windowState', { x: undefined, y: undefined, width: 1200, height: 800, }); const win = new BrowserWindow({ ...windowState, webPreferences: { preload: path.join(__dirname, 'preload.js'), }, }); // 保存窗口状态 win.on('close', () => { const bounds = win.getBounds(); store.set('windowState', { x: bounds.x, y: bounds.y, width: bounds.width, height: bounds.height, }); }); }
// main.js const { Menu } = require('electron'); const template = [ { label: '文件', submenu: [ { label: '新建', accelerator: 'CmdOrCtrl+N', click: () => { // 创建新文件 }, }, { label: '打开', accelerator: 'CmdOrCtrl+O', click: async () => { const result = await dialog.showOpenDialog({ properties: ['openFile'], filters: [ { name: '文本文件', extensions: ['txt', 'md'] }, { name: '所有文件', extensions: ['*'] }, ], }); if (!result.canceled && result.filePaths.length > 0) { const filePath = result.filePaths[0]; mainWindow.webContents.send('file-opened', filePath); } }, }, { type: 'separator' }, { label: '保存', accelerator: 'CmdOrCtrl+S', click: () => {} }, { label: '另存为', accelerator: 'CmdOrCtrl+Shift+S', click: () => {} }, { type: 'separator' }, { role: 'close' }, ], }, { label: '编辑', submenu: [ { role: 'undo', label: '撤销' }, { role: 'redo', label: '重做' }, { type: 'separator' }, { role: 'cut', label: '剪切' }, { role: 'copy', label: '复制' }, { role: 'paste', label: '粘贴' }, { role: 'selectall', label: '全选' }, ], }, { label: '视图', submenu: [ { role: 'reload', label: '重新加载' }, { role: 'forceReload', label: '强制重新加载' }, { role: 'toggleDevTools', label: '开发者工具' }, { type: 'separator' }, { role: 'resetZoom', label: '实际大小' }, { role: 'zoomIn', label: '放大' }, { role: 'zoomOut', label: '缩小' }, { type: 'separator' }, { role: 'togglefullscreen', label: '全屏' }, ], }, { label: '帮助', submenu: [ { label: '关于', click: () => { dialog.showMessageBox({ title: '关于', message: '我的应用', detail: `版本: ${app.getVersion()}`, }); }, }, ], }, ]; // macOS特殊处理:第一个菜单应为应用名 if (process.platform === 'darwin') { template.unshift({ label: app.getName(), submenu: [ { role: 'about' }, { type: 'separator' }, { role: 'services' }, { type: 'separator' }, { role: 'hide' }, { role: 'hideOthers' }, { role: 'unhide' }, { type: 'separator' }, { role: 'quit' }, ], }); } const menu = Menu.buildFromTemplate(template); Menu.setApplicationMenu(menu);
// main.js const { Tray, Menu } = require('electron'); const path = require('path'); let tray; function createTray() { const iconPath = path.join(__dirname, 'assets/tray-icon.png'); tray = new Tray(iconPath); const contextMenu = Menu.buildFromTemplate([ { label: '显示窗口', click: () => { if (mainWindow) { mainWindow.show(); } }, }, { label: '隐藏窗口', click: () => { if (mainWindow) { mainWindow.hide(); } }, }, { type: 'separator' }, { label: '退出', click: () => { app.quit(); }, }, ]); tray.setToolTip('我的应用'); tray.setContextMenu(contextMenu); // 点击托盘图标显示窗口 tray.on('click', () => { if (mainWindow.isVisible()) { mainWindow.hide(); } else { mainWindow.show(); } }); } app.whenReady().then(() => { createWindow(); createTray(); });
npm install electron-updater
// main.js const { autoUpdater } = require('electron-updater'); // 配置自动更新 autoUpdater.setFeedURL({ provider: 'github', owner: 'your-username', repo: 'your-repo', }); // 检查更新 function checkForUpdates() { autoUpdater.checkForUpdatesAndNotify(); } // 更新事件监听 autoUpdater.on('update-available', (info) => { mainWindow.webContents.send('update-available', info); }); autoUpdater.on('update-not-available', (info) => { mainWindow.webContents.send('update-not-available', info); }); autoUpdater.on('download-progress', (progress) => { mainWindow.webContents.send('update-download-progress', progress); }); autoUpdater.on('update-downloaded', (info) => { mainWindow.webContents.send('update-downloaded', info); }); // 渲染进程通知用户 ipcMain.on('install-update', () => { autoUpdater.quitAndInstall(); }); // 应用启动时检查更新 app.whenReady().then(() => { createWindow(); if (process.env.NODE_ENV === 'production') { checkForUpdates(); } });
npm install electron-builder --save-dev
// package.json { "build": { "appId": "com.example.myapp", "productName": "MyApp", "directories": { "output": "dist" }, "files": [ "main.js", "preload.js", "renderer/**/*", "assets/**/*", "node_modules/**/*" ], "mac": { "category": "public.app-category.productivity", "icon": "assets/icon.icns", "target": ["dmg", "zip"] }, "win": { "icon": "assets/icon.ico", "target": ["nsis", "portable"] }, "linux": { "icon": "assets/icon.png", "target": ["AppImage", "deb", "rpm"] } }, "scripts": { "build": "electron-builder", "build:win": "electron-builder --win", "build:mac": "electron-builder --mac", "build:linux": "electron-builder --linux" } }
# 打包所有平台 npm run build # 打包特定平台 npm run build:win npm run build:mac npm run build:linux
new BrowserWindow({ webPreferences: { nodeIntegration: false, // 禁用 contextIsolation: true, // 启用上下文隔离 }, });
mainWindow.webContents.on('will-navigate', (event, url) => { const allowedUrls = ['https://example.com']; if (!allowedUrls.some(allowed => url.startsWith(allowed))) { event.preventDefault(); } }); mainWindow.webContents.on('new-window', (event, url) => { event.preventDefault(); shell.openExternal(url); });
<!-- renderer/index.html --> <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'">
// 只在需要时创建窗口 let preferencesWindow = null; function showPreferences() { if (!preferencesWindow) { preferencesWindow = new BrowserWindow({ width: 600, height: 400, }); preferencesWindow.loadFile('preferences.html'); preferencesWindow.on('closed', () => { preferencesWindow = null; }); } preferencesWindow.show(); }
// 按需加载Node.js模块 async function performHeavyOperation() { const { exec } = await import('child_process'); // 使用exec }
app.commandLine.appendSwitch('js-flags', '--max-old-space-size=4096');
解决方案:
electron-builder的asarUnpack排除不必要的文件electron-forge的@electron-forge/plugin-auto-unpack-nativesTauri或Wails等更轻量的替代方案解决方案:
BrowserWindow的show: false延迟加载解决方案:
| 特性 | Electron | Tauri |
|---|---|---|
| 技术栈 | Chromium + Node.js | WebKit + Rust |
| 应用体积 | ~150MB | ~3MB |
| 内存占用 | 较高 | 较低 |
| 生态系统 | 成熟 | 发展中 |
| 学习曲线 | 适中 | 陡峭(需了解Rust) |
| 适用场景 | 功能复杂的桌面应用 | 轻量级桌面应用 |
Electron依然是2026年最成熟的跨平台桌面应用开发框架:
对于需要快速开发、功能丰富、跨平台的桌面应用,Electron依然是首选方案。虽然出现了Tauri、Wails等更轻量的替代方案,但Electron凭借其成熟度、开发效率和社区支持,依然是构建复杂桌面应用的可靠选择。
关键要点: