Hello World - 桌面记事本

知识库
知识库文档
/tech-stacks/electron/examples/Hello World - 桌面记事本.md

文档

Electron 桌面记事本

目标

用 Electron 创建跨平台桌面记事本应用,展示主进程/渲染进程通信、原生菜单和文件保存。

完整代码

1. 项目初始化

mkdir electron-notepad &;& cd electron-notepad
npm init -y
npm install electron --save-dev

2. package.json

{
  "name": "electron-notepad",
  "version": "1.0.0",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
    "build": "electron-builder"
  }
}

3. main.js

const { app, BrowserWindow, Menu, dialog, ipcMain } = require('electron');
const path = require('path');
const fs = require('fs');

let mainWindow;

function createWindow() {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      contextIsolation: true,
      nodeIntegration: false,
    },
  });

  mainWindow.loadFile('index.html');

  // 原生菜单
  const menuTemplate = [
    {
      label: '文件',
      submenu: [
        {
          label: '打开',
          accelerator: 'CmdOrCtrl+O',
          click: async () => {
            const { filePaths } = await dialog.showOpenDialog({ filters: [{ name: '文本文件', extensions: ['txt'] }] });
            if (filePaths[0]) {
              const content = fs.readFileSync(filePaths[0], 'utf-8');
              mainWindow.webContents.send('file-opened', content);
            }
          },
        },
        {
          label: '保存',
          accelerator: 'CmdOrCtrl+S',
          click: () => mainWindow.webContents.send('trigger-save'),
        },
        { type: 'separator' },
        { label: '退出', accelerator: 'CmdOrCtrl+Q', click: () => app.quit() },
      ],
    },
    {
      label: '帮助',
      submenu: [
        { label: '关于', click: () => dialog.showMessageBox({ title: '关于', message: '桌面记事本 v1.0\n毕设参考项目' }) },
      ],
    },
  ];

  Menu.setApplicationMenu(Menu.buildFromTemplate(menuTemplate));
}

// IPC: 保存文件
ipcMain.handle('save-file', async (event, content) => {
  const { filePath } = await dialog.showSaveDialog({ filters: [{ name: '文本文件', extensions: ['txt'] }] });
  if (filePath) {
    fs.writeFileSync(filePath, content, 'utf-8');
    return { success: true, path: filePath };
  }
  return { success: false };
});

app.whenReady().then(createWindow);
app.on('window-all-closed', () => { if (process.platform !== 'darwin') app.quit(); });
app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) createWindow(); });

4. preload.js

const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('electronAPI', {
  onFileOpened: (callback) => ipcRenderer.on('file-opened', (_, content) => callback(content)),
  onTriggerSave: (callback) => ipcRenderer.on('trigger-save', () => callback()),
  saveFile: (content) => ipcRenderer.invoke('save-file', content),
});

5. index.html

<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8">
  <title>桌面记事本</title>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body { font-family: system-ui; }
    .toolbar { display: flex; gap: 8px; padding: 10px; background: #f1f5f9; border-bottom: 1px solid #e2e8f0; }
    .toolbar button { padding: 6px 14px; border: 1px solid #cbd5e1; background: white; border-radius: 4px; cursor: pointer; }
    .toolbar button:hover { background: #e2e8f0; }
    .info { margin-left: auto; color: #64748b; font-size: 0.85em; display: flex; align-items: center; }
    textarea { width: 100%; height: calc(100vh - 48px); padding: 16px; font-size: 16px; border: none; resize: none; outline: none; font-family: 'Fira Code', monospace; line-height: 1.6; }
  </style>
</head>
<body>
  <div class="toolbar">
    <button onclick="newFile()">📄 新建</button>
    <button onclick="saveFile()">💾 保存</button>
    <span class="info" id="status"></span>
  </div>
  <textarea id="editor" placeholder="在此输入..." autofocus></textarea>

  <script>
    const editor = document.getElementById('editor');
    const status = document.getElementById('status');

    // 打开文件时加载内容
    window.electronAPI?.onFileOpened((content) => {
      editor.value = content;
      status.textContent = '已打开文件';
    });

    // 菜单保存触发
    window.electronAPI?.onTriggerSave(() => saveFile());

    async function saveFile() {
      const result = await window.electronAPI?.saveFile(editor.value);
      if (result?.success) {
        status.textContent = `已保存: ${result.path}`;
        setTimeout(() => status.textContent = '', 2000);
      }
    }

    function newFile() {
      if (editor.value && !confirm('未保存的内容将丢失,确认新建?')) return;
      editor.value = '';
      status.textContent = '';
    }

    // 字数统计
    editor.addEventListener('input', () => {
      document.title = `记事本 - ${editor.value.length} 字`;
    });

    // Ctrl+S 快捷键
    document.addEventListener('keydown', (e) => {
      if ((e.ctrlKey || e.metaKey) && e.key === 's') {
        e.preventDefault();
        saveFile();
      }
    });
  </script>
</body>
</html>

运行步骤

npm start

预期输出

  • 打开桌面窗口,显示文本编辑器
  • 菜单栏 → 文件 → 打开/保存(原生对话框)
  • Ctrl+S 保存文件到本地
  • 窗口标题显示实时字数

信息

路径
/tech-stacks/electron/examples/Hello World - 桌面记事本.md
更新时间
2026/5/30