第一个应用 #
一、项目初始化 #
1.1 创建项目 #
bash
# 创建项目目录
mkdir my-first-electron-app
cd my-first-electron-app
# 初始化项目
npm init -y
1.2 安装依赖 #
bash
# 安装 Electron
npm install electron --save-dev
1.3 修改 package.json #
json
{
"name": "my-first-electron-app",
"version": "1.0.0",
"description": "我的第一个 Electron 应用",
"main": "main.js",
"scripts": {
"start": "electron .",
"dev": "electron . --enable-logging"
},
"devDependencies": {
"electron": "^28.0.0"
}
}
二、创建主进程 #
2.1 主进程文件 #
创建 main.js 文件:
javascript
const { app, BrowserWindow } = require('electron');
const path = require('path');
function createWindow() {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: false,
contextIsolation: true
}
});
mainWindow.loadFile('index.html');
mainWindow.webContents.openDevTools();
}
app.whenReady().then(() => {
createWindow();
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
2.2 代码解析 #
| 代码 | 说明 |
|---|---|
app |
控制应用生命周期的模块 |
BrowserWindow |
创建浏览器窗口的模块 |
createWindow() |
创建窗口的函数 |
webPreferences |
网页偏好设置 |
preload |
预加载脚本路径 |
app.whenReady() |
应用初始化完成回调 |
app.quit() |
退出应用 |
三、创建预加载脚本 #
3.1 预加载脚本文件 #
创建 preload.js 文件:
javascript
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
send: (channel, data) => {
const validChannels = ['toMain'];
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data);
}
},
receive: (channel, func) => {
const validChannels = ['fromMain'];
if (validChannels.includes(channel)) {
ipcRenderer.on(channel, (event, ...args) => func(...args));
}
}
});
3.2 预加载脚本作用 #
text
┌─────────────────┐
│ 渲染进程 │
│ (Web 页面) │
└────────┬────────┘
│
▼
┌─────────────────┐
│ 预加载脚本 │ ← 安全桥梁
│ (preload.js) │
└────────┬────────┘
│
▼
┌─────────────────┐
│ 主进程 │
│ (Node.js) │
└─────────────────┘
核心作用:
- 安全地暴露 Node.js API 给渲染进程
- 实现主进程与渲染进程的通信
- 隔离渲染进程与主进程的直接访问
四、创建渲染进程 #
4.1 HTML 页面 #
创建 index.html 文件:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>我的第一个 Electron 应用</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<h1>你好,Electron!</h1>
<p>这是我的第一个 Electron 应用</p>
<div class="info">
<p>Node.js 版本: <span id="node-version"></span></p>
<p>Chromium 版本: <span id="chrome-version"></span></p>
<p>Electron 版本: <span id="electron-version"></span></p>
</div>
<button id="btn">点击我</button>
<p id="message"></p>
</div>
<script src="renderer.js"></script>
</body>
</html>
4.2 CSS 样式 #
创建 styles.css 文件:
css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.container {
background: white;
padding: 40px;
border-radius: 16px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
text-align: center;
max-width: 400px;
}
h1 {
color: #333;
margin-bottom: 10px;
}
p {
color: #666;
margin-bottom: 20px;
}
.info {
background: #f5f5f5;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
text-align: left;
}
.info p {
margin-bottom: 8px;
font-size: 14px;
}
.info span {
color: #667eea;
font-weight: bold;
}
button {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 12px 30px;
font-size: 16px;
border-radius: 8px;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
}
button:hover {
transform: translateY(-2px);
box-shadow: 0 5px 20px rgba(102, 126, 234, 0.4);
}
button:active {
transform: translateY(0);
}
#message {
margin-top: 15px;
color: #667eea;
font-weight: bold;
}
4.3 渲染进程脚本 #
创建 renderer.js 文件:
javascript
// 显示版本信息
document.getElementById('node-version').innerText = process.versions.node;
document.getElementById('chrome-version').innerText = process.versions.chrome;
document.getElementById('electron-version').innerText = process.versions.electron;
// 按钮点击事件
let clickCount = 0;
document.getElementById('btn').addEventListener('click', () => {
clickCount++;
document.getElementById('message').innerText = `你已经点击了 ${clickCount} 次!`;
});
五、运行应用 #
5.1 启动应用 #
bash
npm start
5.2 预期效果 #
text
┌────────────────────────────────────────┐
│ 我的第一Electron应用 ─ □ × │
├────────────────────────────────────────┤
│ │
│ 你好,Electron! │
│ 这是我的第一个 Electron 应用 │
│ │
│ ┌────────────────────────────────┐ │
│ │ Node.js 版本: 20.x.x │ │
│ │ Chromium 版本: 120.x.x │ │
│ │ Electron 版本: 28.x.x │ │
│ └────────────────────────────────┘ │
│ │
│ [ 点击我 ] │
│ │
│ 你已经点击了 1 次! │
│ │
└────────────────────────────────────────┘
六、项目结构 #
6.1 完整结构 #
text
my-first-electron-app/
├── index.html # 渲染进程页面
├── main.js # 主进程入口
├── preload.js # 预加载脚本
├── renderer.js # 渲染进程脚本
├── styles.css # 样式文件
├── package.json # 项目配置
└── node_modules/ # 依赖目录
6.2 文件说明 #
| 文件 | 作用 | 运行环境 |
|---|---|---|
| main.js | 主进程入口,管理应用生命周期 | Node.js |
| preload.js | 预加载脚本,安全桥梁 | Node.js (受限) |
| index.html | 应用界面 | Chromium |
| renderer.js | 页面交互逻辑 | Chromium |
| styles.css | 页面样式 | Chromium |
七、代码详解 #
7.1 主进程详解 #
javascript
// 引入模块
const { app, BrowserWindow } = require('electron');
const path = require('path');
// 创建窗口函数
function createWindow() {
// 创建浏览器窗口
const mainWindow = new BrowserWindow({
width: 800, // 窗口宽度
height: 600, // 窗口高度
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: false, // 禁用 Node.js 集成
contextIsolation: true // 启用上下文隔离
}
});
// 加载 HTML 文件
mainWindow.loadFile('index.html');
// 打开开发者工具(开发模式)
mainWindow.webContents.openDevTools();
}
// 应用准备就绪时创建窗口
app.whenReady().then(() => {
createWindow();
// macOS 特殊处理:点击 dock 图标时重新创建窗口
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
// 所有窗口关闭时退出应用(Windows/Linux)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
7.2 窗口配置选项 #
javascript
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
minWidth: 400,
minHeight: 300,
maxWidth: 1200,
maxHeight: 900,
x: 100,
y: 100,
center: true,
resizable: true,
movable: true,
minimizable: true,
maximizable: true,
closable: true,
focusable: true,
alwaysOnTop: false,
fullscreen: false,
fullscreenable: true,
title: '我的应用',
icon: '/path/to/icon.png',
frame: true,
transparent: false,
backgroundColor: '#fff',
show: true,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
enableRemoteModule: false,
preload: path.join(__dirname, 'preload.js')
}
});
7.3 生命周期事件 #
javascript
// 应用启动完成
app.on('ready', () => {
console.log('应用准备就绪');
});
// 应用激活
app.on('activate', () => {
console.log('应用被激活');
});
// 所有窗口关闭
app.on('window-all-closed', () => {
console.log('所有窗口已关闭');
});
// 应用退出前
app.on('before-quit', () => {
console.log('应用即将退出');
});
// 应用退出
app.on('will-quit', () => {
console.log('应用正在退出');
});
// 应用已退出
app.on('quit', () => {
console.log('应用已退出');
});
八、调试技巧 #
8.1 主进程调试 #
方式一:控制台输出
javascript
console.log('主进程日志');
方式二:VS Code 调试
json
// .vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Main Process",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"args": ["."],
"outputCapture": "std"
}
]
}
8.2 渲染进程调试 #
javascript
// 在主进程中打开开发者工具
mainWindow.webContents.openDevTools();
// 或使用快捷键
// Windows/Linux: Ctrl + Shift + I
// macOS: Cmd + Option + I
8.3 查看版本信息 #
javascript
// 在渲染进程中
console.log('Node:', process.versions.node);
console.log('Chrome:', process.versions.chrome);
console.log('Electron:', process.versions.electron);
console.log('V8:', process.versions.v8);
九、常见问题 #
9.1 白屏问题 #
javascript
// 检查文件路径
mainWindow.loadFile(path.join(__dirname, 'index.html'));
// 监听加载错误
mainWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription) => {
console.error('页面加载失败:', errorDescription);
});
9.2 安全警告 #
javascript
// 禁用安全警告(仅开发环境)
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = 'true';
// 或正确配置 CSP
// <meta http-equiv="Content-Security-Policy" content="default-src 'self'">
9.3 预加载脚本错误 #
javascript
// 检查预加载脚本路径
console.log('Preload path:', path.join(__dirname, 'preload.js'));
// 确保文件存在
const fs = require('fs');
if (fs.existsSync(path.join(__dirname, 'preload.js'))) {
console.log('预加载脚本存在');
}
十、总结 #
10.1 核心要点 #
| 要点 | 说明 |
|---|---|
| 主进程 | 管理应用生命周期和原生功能 |
| 渲染进程 | 显示 Web 页面,处理用户交互 |
| 预加载脚本 | 安全地连接主进程和渲染进程 |
| 窗口配置 | BrowserWindow 的各种选项 |
10.2 下一步 #
现在你已经创建了第一个 Electron 应用,接下来让我们学习 项目结构,了解如何组织一个规范的 Electron 项目!
最后更新:2026-03-28