项目介绍
这是一个基于Electron开发的右键菜单组件示例项目,展示了如何在桌面应用中实现功能丰富的右键菜单系统。该项目同时演示了Electron原生右键菜单和自定义Web右键菜单的实现方式,支持多种上下文(文本、图片、输入框等)的右键菜单定制,为桌面应用提供更灵活的交互体验。

功能特点
- 原生右键菜单:使用Electron的Menu API实现系统级原生右键菜单
- 自定义Web右键菜单:使用HTML/CSS/JS实现的完全可控的右键菜单
- 上下文感知:根据不同内容类型(文本、图片、输入框)显示不同的右键菜单
- 多级菜单支持:支持一级菜单和二级子菜单
- 图标支持:为菜单项添加直观的图标
- 键盘导航:支持ESC键关闭右键菜单
- 响应式设计:自适应不同屏幕尺寸
- 事件回调:为菜单项绑定自定义操作处理函数
- 菜单定位:智能定位菜单,避免超出屏幕边界
技术实现
主进程(main.js)
主进程负责创建和管理Electron的原生右键菜单,处理不同上下文的菜单需求:
javascript
// 构建原生右键菜单
const mainContextMenu = Menu.buildFromTemplate([
{
label: '撤销',
role: 'undo',
accelerator: 'CmdOrCtrl+Z'
},
// 更多菜单项...
]);
// 监听右键菜单事件
mainWindow.webContents.on('context-menu', (event, params) => {
// 根据上下文显示不同的右键菜单
if (params.mediaType === 'image') {
// 显示图片右键菜单
imageContextMenu.popup({ window: mainWindow, x: params.x, y: params.y });
} else if (params.selectionText) {
// 显示文本右键菜单
textContextMenu.popup({ window: mainWindow, x: params.x, y: params.y });
} else {
// 显示默认右键菜单
mainContextMenu.popup({ window: mainWindow, x: params.x, y: params.y });
}
event.preventDefault();
});
预加载脚本(preload.js)
使用contextBridge安全地暴露API到渲染进程,实现主进程和渲染进程之间的通信:
javascript
contextBridge.exposeInMainWorld('electronAPI', {
// 显示上下文菜单
showContextMenu: (menuType, eventData) => {
ipcRenderer.send('show-context-menu', menuType, eventData);
},
// 监听主进程的消息
on: (channel, callback) => {
const validChannels = [
'copy-image', 'open-image-new-window', 'save-image',
'copy-image-link', 'search-text', 'copy-as-html'
];
if (validChannels.includes(channel)) {
const newCallback = (event, ...args) => callback(...args);
ipcRenderer.on(channel, newCallback);
return () => ipcRenderer.removeListener(channel, newCallback);
}
}
});
渲染进程(renderer.js)
渲染进程实现了自定义Web右键菜单和与主进程的交互逻辑:
javascript
// 右键菜单管理器类
class ContextMenuManager {
constructor() {
this.menus = new Map();
this.activeMenu = null;
}
// 注册新的右键菜单
register(menuId, menuDefinition) {
this.menus.set(menuId, menuDefinition);
}
// 为元素绑定右键菜单
bind(element, menuId) {
// 实现元素绑定逻辑
}
// 显示和隐藏菜单方法
show(menuId, x, y) { /* ... */ }
hide() { /* ... */ }
}
// 导出实例
window.ContextMenuManager = new ContextMenuManager();
代码结构
86-context-menu/
├── main.js # Electron主进程文件,处理原生右键菜单
├── preload.js # 预加载脚本,处理进程间通信
├── index.html # 应用主界面HTML
├── style.css # 样式文件,包含右键菜单样式
├── renderer.js # 渲染进程JavaScript,实现自定义右键菜单逻辑
├── package.json # 项目配置和依赖
└── README.md # 项目说明文档
核心代码示例
1. 自定义右键菜单显示/隐藏功能
javascript
// 显示自定义右键菜单
function showCustomContextMenu(x, y) {
const customContextMenu = document.getElementById('custom-context-menu');
// 设置菜单位置
customContextMenu.style.left = `${x}px`;
customContextMenu.style.top = `${y}px`;
// 检查边界,确保菜单不会超出视口
const rect = customContextMenu.getBoundingClientRect();
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
// 调整位置避免超出边界
if (rect.right > viewportWidth) {
customContextMenu.style.left = `${x - rect.width}px`;
}
if (rect.bottom > viewportHeight) {
customContextMenu.style.top = `${y - rect.height}px`;
}
// 显示菜单
customContextMenu.classList.add('show');
}
// 隐藏自定义右键菜单
function hideCustomContextMenu() {
const customContextMenu = document.getElementById('custom-context-menu');
customContextMenu.classList.remove('show');
}
2. 菜单项事件处理
javascript
// 处理自定义菜单项点击动作
function handleCustomMenuAction(action) {
// 根据动作类型执行相应操作
switch (action) {
case 'action1':
showToast('区域已收藏');
break;
case 'action2':
showToast('编辑模式已激活');
break;
case 'style-red':
customMenuArea.style.backgroundColor = '#fff1f0';
showToast('已应用红色主题');
break;
// 更多动作...
}
}
3. 主进程与渲染进程通信
javascript
// 在渲染进程中监听主进程消息
window.electronAPI.on('copy-image', () => {
showToast('图片已复制到剪贴板');
});
window.electronAPI.on('open-image-new-window', () => {
showToast('将在新窗口中打开图片');
const demoImage = document.getElementById('demo-image');
if (demoImage) {
window.open(demoImage.src, '_blank');
}
});
如何运行
-
确保已安装Node.js环境
-
在项目根目录执行以下命令:
bash# 安装依赖 npm install # 启动应用 npm start
扩展建议
- 添加键盘快捷键支持:为菜单项添加快捷键提示和处理
- 实现动态菜单:根据应用状态动态生成菜单项
- 自定义主题:允许用户自定义右键菜单的样式
- 支持菜单项图标:使用自定义图标替代emoji
- 添加菜单项状态:支持选中、禁用等状态
- 实现拖拽功能:允许用户拖拽菜单项重新排序
- 集成国际化:支持多语言菜单项
注意事项
- 在Electron中同时使用原生和自定义右键菜单时,需要注意正确处理事件阻止
- 自定义右键菜单在跨平台使用时可能需要进行样式调整以适应不同系统
- 菜单项的命名应简洁明了,符合用户习惯
- 对于复杂的菜单结构,应考虑使用子菜单来组织
- 菜单的显示位置应避免超出视口边界
- 在实现菜单项功能时,应提供适当的用户反馈(如操作提示)
- 对于常用操作,应考虑添加键盘快捷键以提高效率
鸿蒙PC适配改造指南
1. 环境准备
-
系统要求:Windows 10/11、8GB RAM以上、20GB可用空间
-
工具安装 :
DevEco Studio 5.0+(安装鸿蒙SDK API 20+)
-
Node.js 18.x+
2. 获取Electron鸿蒙编译产物
-
下载Electron 34+版本的Release包(.zip格式)
-
解压到项目目录,确认
electron/libs/arm64-v8a/下包含核心.so库
3. 部署应用代码
将Electron应用代码按以下目录结构放置:

plaintext
web_engine/src/main/resources/resfile/resources/app/
├── main.js
├── package.json
└── src/
├── index.html
├── preload.js
├── renderer.js
└── style.css
4. 配置与运行
-
打开项目:在DevEco Studio中打开ohos_hap目录
-
配置签名 :
进入File → Project Structure → Signing Configs
-
自动生成调试签名或导入已有签名
-
连接设备 :
启用鸿蒙设备开发者模式和USB调试
-
通过USB Type-C连接电脑
-
编译运行:点击Run按钮或按Shift+F10
5. 验证检查项
-
✅ 应用窗口正常显示
-
✅ 窗口大小可调整,响应式布局生效
-
✅ 控制台无"SysCap不匹配"或"找不到.so文件"错误
-
✅ 动画效果正常播放
跨平台兼容性
| 平台 | 适配策略 | 特殊处理 |
|---|---|---|
| Windows | 标准Electron运行 | 无特殊配置 |
| macOS | 标准Electron运行 | 保留dock图标激活逻辑 |
| Linux | 标准Electron运行 | 确保系统依赖库完整 |
| 鸿蒙PC | 通过Electron鸿蒙适配层 | 禁用硬件加速,使用特定目录结构 |
鸿蒙开发调试技巧
1. 日志查看
在DevEco Studio的Log面板中过滤"Electron"关键词,查看应用运行日志和错误信息。
2. 常见问题解决
-
"SysCap不匹配"错误:检查module.json5中的reqSysCapabilities,只保留必要系统能力
-
"找不到.so文件"错误:确认arm64-v8a目录下四个核心库文件完整
-
窗口不显示:在main.js中添加app.disableHardwareAcceleration()
-
动画卡顿:简化CSS动画效果,减少重绘频率