第一个应用 #

一、项目初始化 #

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