当前位置: 首页 > java >正文

Electron Forge【实战】自定义菜单 -- 顶部菜单 vs 右键快捷菜单

效果预览

在这里插入图片描述
在这里插入图片描述

定义菜单 src/menu.ts

import { Menu, BrowserWindow, MenuItemConstructorOptions } from "electron";import { configManager } from "./config";
import en from "./language/en";
import zh from "./language/zh";type MessageSchema = typeof zh;
const messages: Record<string, MessageSchema> = {en,zh,
};// 创建一个通用的翻译函数
const createTranslator = () => {const config = configManager.get();return (key: string) => {const keys = key.split(".");let result: any = messages[config.language];for (const k of keys) {result = result[k];}return result as string;};
};// 顶部菜单
const createMenu = (mainWindow: BrowserWindow) => {const t = createTranslator();const template: MenuItemConstructorOptions[] = [{label: t("menu.app.myApp"),submenu: [{label: t("menu.app.newConversation"),accelerator: "CmdOrCtrl+N",click: () => {mainWindow.webContents.send("menu-new-conversation");},},{label: t("menu.app.settings"),accelerator: "CmdOrCtrl+,",click: () => {mainWindow.webContents.send("menu-open-settings");},},{ type: "separator" },{role: "quit",label: t("menu.app.quit"),},],},{label: t("menu.edit.title"),submenu: [{role: "undo",label: t("menu.edit.undo"),},{role: "redo",label: t("menu.edit.redo"),},{ type: "separator" },{role: "cut",label: t("menu.edit.cut"),},{role: "copy",label: t("menu.edit.copy"),},{role: "paste",label: t("menu.edit.paste"),},{role: "selectAll",label: t("menu.edit.selectAll"),},...(process.platform === "darwin"? ([{ type: "separator" as const },{label: t("menu.edit.speech.title"),submenu: [{role: "startSpeaking",label: t("menu.edit.speech.startSpeaking"),},{role: "stopSpeaking",label: t("menu.edit.speech.stopSpeaking"),},],},{role: "emoji",label: t("menu.edit.emoji"),},] as MenuItemConstructorOptions[]): []),],},{label: t("menu.view.title"),submenu: [{role: "reload",label: t("menu.view.reload"),},{role: "forceReload",label: t("menu.view.forceReload"),},{role: "toggleDevTools",label: t("menu.view.toggleDevTools"),},{ type: "separator" },{role: "resetZoom",label: t("menu.view.resetZoom"),},{role: "zoomIn",label: t("menu.view.zoomIn"),},{role: "zoomOut",label: t("menu.view.zoomOut"),},{ type: "separator" },{role: "togglefullscreen",label: t("menu.view.togglefullscreen"),},],},...(process.platform === "darwin"? [{role: "windowMenu" as const,},]: []),];const menu = Menu.buildFromTemplate(template);Menu.setApplicationMenu(menu);
};// 右键菜单
const createContextMenu = (win: BrowserWindow, id: number) => {const t = createTranslator();const template = [{label: t("contextMenu.deleteConversation"),click: () => {win.webContents.send("delete-conversation", id);},},];const menu = Menu.buildFromTemplate(template);menu.popup({ window: win });
};// 导出一个更新菜单的函数,在语言改变时调用
const updateMenu = (mainWindow: BrowserWindow) => {createMenu(mainWindow);
};export { createMenu, updateMenu, createContextMenu };

顶部菜单

加载顶部菜单 src/main.ts

import { createMenu } from "./menu";
  // 加载菜单createMenu(mainWindow);

添加 IPC 通信 src/preload.ts

  onMenuNewConversation: (callback: () => void) =>ipcRenderer.on("menu-new-conversation", () => callback()),onMenuOpenSettings: (callback: () => void) =>ipcRenderer.on("menu-open-settings", () => callback()),

全局监听菜单事件 src/App.vue

// 监听菜单事件
window.electronAPI.onMenuNewConversation(() => {router.push("/");
});window.electronAPI.onMenuOpenSettings(() => {router.push("/settings");
});

修改设置时,更新顶部菜单 src/ipc.ts

import { createContextMenu, updateMenu } from "./menu";
  ipcMain.handle("update-config", async (event, newConfig) => {const updatedConfig = await configManager.update(newConfig);// 如果语言发生变化,更新菜单if (newConfig.language) {updateMenu(mainWindow);}return updatedConfig;});

右键快捷菜单

目标元素上添加右键快捷菜单事件

src/components/ConversationList.vue

@contextmenu.prevent="showContextMenu(item.id)"
const showContextMenu = (id: number) => {window.electronAPI.showContextMenu(id);
};

添加 IPC 通信

src/preload.ts

  // 显示右键菜单showContextMenu: (id: number) => ipcRenderer.send("show-context-menu", id),// 删除会话onDeleteConversation: (callback: (id: number) => void) =>ipcRenderer.on("delete-conversation", (_event, id) => callback(id)),

src/ipc.ts

import { createContextMenu, updateMenu } from "./menu";
  // 弹出右键菜单ipcMain.on("show-context-menu", (event, id) => {const win = BrowserWindow.fromWebContents(event.sender);if (!win) return;createContextMenu(win, id);});

页面响应右键快捷菜单事件

src/components/ConversationList.vue

onMounted(() => {window.electronAPI.onDeleteConversation(async (id: number) => {await store.deleteConversation(id);if (store.selectedId === id) {store.selectedId = -1;router.push("/");}});
});
http://www.xdnf.cn/news/3219.html

相关文章:

  • 百度网盘golang实习面经
  • HTML from表单中只有一个input时,按回车键后表单自动提交(form表单的一个小坑)
  • 【C++】频繁分配和释放会产生内存碎片
  • Win下的Kafka安装配置
  • Tauri v1 与 v2 配置对比
  • 全面解析SimHash算法:原理、对比与Spring Boot实践指南
  • transformer-实现解码器Decoder
  • DIT(Diffusion In Transformer)学习笔记
  • Java继承中super的使用方法
  • SI5338-EVB Usage Guide(LVPECL、LVDS、HCSL、CMOS、SSTL、HSTL)
  • 电子病历高质量语料库构建方法与架构项目(智能数据目录篇)
  • SD - WAN 跨境网络专线部署方式介绍
  • 大数据在远程医疗中的创新应用:如何重塑医疗行业的未来
  • python + segno 生成个人二维码
  • 全球气象站点年平均降水数据(1929-2024)
  • 大连理工大学选修课——机器学习笔记(4):NBM的原理及应用
  • 大连理工大学选修课——机器学习笔记(9):线性判别式与逻辑回归
  • 使用 ossutil 上传文件到阿里云 OSS
  • 基于连接感知的实时困倦分类图神经网络
  • 【数学】角谷猜想
  • 服务器热备份,服务器热备份的方法有哪些?
  • 猿人学web端爬虫攻防大赛赛题第13题——入门级cookie
  • 完美解决react-native文件直传阿里云oss问题一
  • Android学习总结之自定义view设计模式理解
  • Redis热key大key详解
  • ESP32开发-通过ENC28J60模块实现以太网设备
  • 从实列中学习linux shell6: 写一个 shell 脚本 过滤 恶意ip 攻击
  • css 数字从0开始增加的动画效果
  • 【数学建模国奖速成系列】优秀论文绘图复现代码(二)
  • DeepSeek V1:初代模型的架构与性能