You need to enable JavaScript to run this app. Electron.js如何在渲染进程中处理全局快捷键与文件菜单点击事件
优惠活动
大模型
产品
解决方案
定价
更多

Electron.js如何在渲染进程中处理全局快捷键与文件菜单点击事件

解决方案

前置说明

Electron 主进程向渲染进程通信核心依赖 webContents.send() 方法,结合上下文隔离环境下的 preload 脚本暴露 IPC 接口即可实现,以下是适配 electron-forge + TypeScript 环境的具体实现:

步骤1:配置 preload 脚本(核心)

electron-forge 默认开启上下文隔离,你需要先在 preload.ts 中通过 contextBridge 暴露跨进程通信接口:

// preload.ts
import { contextBridge, ipcRenderer } from 'electron';

contextBridge.exposeInMainWorld('electronAPI', {
  // 监听主进程发来的事件
  on: (channel: string, callback: (...args: any[]) => void) => {
    ipcRenderer.on(channel, (_, ...args) => callback(...args));
  },
  // 向主进程发送消息
  send: (channel: string, ...args: any[]) => {
    ipcRenderer.send(channel, ...args);
  }
});

同时新增类型声明文件 global.d.ts 避免 TS 类型报错:

// global.d.ts
export {};
declare global {
  interface Window {
    electronAPI: {
      on: (channel: string, callback: (...args: any[]) => void) => void;
      send: (channel: string, ...args: any[]) => void;
    };
  }
}

创建窗口时记得在 webPreferences 中配置 preload 脚本路径。

步骤2:主进程侧发送消息逻辑

首先需要存储你创建的 BrowserWindow 实例,后续通过该实例的 webContents.send() 方法向渲染进程发消息:

2.1 全局快捷键触发时发消息

// index.ts 主进程
import { app, BrowserWindow, globalShortcut, Menu, dialog, ipcMain } from 'electron';
import * as fs from 'fs';
import * as path from 'path';

let mainWindow: BrowserWindow | null;
// 你的窗口创建逻辑
function createWindow() {
  mainWindow = new BrowserWindow({
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'), // 替换为你的preload实际路径
      contextIsolation: true,
      nodeIntegration: false
    }
  });
  mainWindow.loadFile('index.html');
}

在全局快捷键注册逻辑中调用发送方法:

app.whenReady().then(() => {
  // 示例:注册全局保存快捷键
  globalShortcut.register('CommandOrControl+S', () => {
    // 向渲染进程发送快捷键触发事件,第二个参数为自定义参数
    mainWindow?.webContents.send('global-shortcut-trigger', 'save');
  });
});

2.2 File菜单触发时发消息

在菜单模板的点击回调中发送对应事件:

const menuTemplate = [
  {
    label: 'File',
    submenu: [
      {
        label: 'Save',
        accelerator: 'CommandOrControl+S',
        click: () => mainWindow?.webContents.send('file-save-request')
      },
      {
        label: 'Save As',
        click: () => mainWindow?.webContents.send('file-save-as-request')
      },
      {
        label: 'Load File',
        click: () => mainWindow?.webContents.send('file-load-request')
      }
    ]
  }
];
Menu.setApplicationMenu(Menu.buildFromTemplate(menuTemplate));

同时补充主进程侧的文件读写逻辑,监听渲染进程发来的文件操作请求:

// 监听保存请求
ipcMain.on('save-file', async (_, content: string, isSaveAs: boolean) => {
  if (!mainWindow) return;
  const filePath = isSaveAs ? 
    (await dialog.showSaveDialog(mainWindow)).filePath : 
    // 这里可以存储上次保存的路径复用,逻辑自行补充
    (await dialog.showSaveDialog(mainWindow)).filePath;
  if (filePath) {
    fs.writeFileSync(filePath, content, 'utf-8');
  }
});
// 监听加载请求
ipcMain.on('load-file', async () => {
  if (!mainWindow) return;
  const { filePaths } = await dialog.showOpenDialog(mainWindow, {
    properties: ['openFile'],
    filters: [{ name: 'Text Files', extensions: ['txt', 'md'] }]
  });
  if (filePaths?.length) {
    const content = fs.readFileSync(filePaths[0], 'utf-8');
    // 读取完成后把内容发给渲染进程
    mainWindow.webContents.send('file-content-loaded', content);
  }
});

步骤3:渲染进程侧监听事件处理DOM

在 renderer.ts 中监听主进程发来的事件,直接操作 textarea 元素即可:

// renderer.ts
const textarea = document.querySelector('textarea') as HTMLTextAreaElement;

// 监听全局快捷键触发
window.electronAPI.on('global-shortcut-trigger', (action: string) => {
  if (action === 'save') {
    // 拿到textarea内容发给主进程保存
    window.electronAPI.send('save-file', textarea.value, false);
  }
});

// 监听菜单Save请求
window.electronAPI.on('file-save-request', () => {
  window.electronAPI.send('save-file', textarea.value, false);
});

// 监听菜单Save As请求
window.electronAPI.on('file-save-as-request', () => {
  window.electronAPI.send('save-file', textarea.value, true);
});

// 监听菜单Load请求
window.electronAPI.on('file-load-request', () => {
  window.electronAPI.send('load-file');
});

// 监听主进程返回的加载文件内容
window.electronAPI.on('file-content-loaded', (content: string) => {
  textarea.value = content;
});

内容的提问来源于stack exchange,提问作者pokemon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.14 10:45:06