Electron上下文菜单创建


最近做公司项目,由于是个聊天项目,有用到上下文菜单的需求(右键删除聊天记录等),网上方法参差不齐,整理了下自己的思路。

什么是上下文菜单呢,其实就是右键菜单,右击某块区域弹出的菜单你们城里人说话就是不一样

渲染进程实现

首先在需要实现的页面引入必要的组件,上下文菜单的实现需要Menu模块

诶注意,别直接傻傻引进来了,渲染进程是不能使用 electron 组件的,这个时候就需要用到remote

remote模块,说白了就是让你在渲染进程中也能使用主进程模块的东西,引入代码如下

1
2
import { remote } from 'electron'
const { Menu } = remote

有两种实现方法,先说个人认为比较麻烦但好理解的一种

创建一个船新的空Menu

此方法需要引入MenuItem,我们把上面的引入稍微修改一下

1
const { Menu, MenuItem } = remote

步骤为:

  • 创建一个船新的空Menu
  • 将数个MenuItem塞到Menu
  • 最后通过popup()控制Menu显示的显示
    popup()内可以传递一个作用区域(BrowserWindow对象),其他参数见下图(来自官方文档Menu篇)

popup参数
代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 创建新的空菜单
const menu = new Menu()
// 添加第一个子菜单
menu.append(new MenuItem({
label: 'item1',
click: function() {
// 执行方法
}
}))
// 添加第二个子菜单(子菜单)
menu.append(new MenuItem({
label: 'item2',
submenu: [{
label: 'item2-1',
click: () => {
// 执行方法
}
}]
}))
// 添加第三个子菜单
// menu.append(...)
// 把Menu展示出来
menu.popup(remote.getCurrentWindow())

比较好懂对不对?无非就是创建个空菜单,然后不停的往里一条一条的塞东西,但,岂不是太麻烦了点?

直接通过对象创建Menu

这个就相对省事了,创建一个模板对象, 然后使用buildFromTemplate()直接通过模板对象创建一个Menu,再通过popup()控制Menu显示的显示即可,还不需要引入 MenuItem,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 创建模板对象
const contextTemplate = [{
label: 'item1',
click: () => {
// 执行方法
}
},{
label: 'item2',
submenu: [{
label: 'item2-1',
click: () => {
// 执行方法
}
}]
}]
// 使用模板对象创建Menu
const contextMenu = Menu.buildFromTemplate(contextTemplate)
// 把Menu展示出来
menu.popup(remote.getCurrentWindow())

逻辑清晰了不少吧?个人更喜欢用第二种方法,当然还是各取所需啦,而且第二种方法创建的contextMenu也可以使用append()额外添加新的MenuItem的,不冲突

*更多的MenuItem属性可以参考官方文档

主进程实现

当然如果嫌麻烦或者不想在渲染进程实现的话,主进程也是可以的(即background.js),主线程中不需要使用remote,可以直接从electron中引入 Menu、MenuItem,需要使用ipcMain进程通讯模块来通知渲染线程,创建方法省略,和上面没什么区别,大体说一下进程通讯

主进程内
1
2
3
4
5
6
7
8
// 引入进程通讯模块
import { ipcMain } from 'electron'
// 启动监听事件
ipcMain.on('show-context-menu', (e) => {
// win 为触发该事件所在的窗口
const win = BrowserWindow.fromWebContents(e.sender)
menu.popup(win)
})
渲染进程内
1
2
3
4
// 引入进程通讯模块
import { ipcRenderer } from 'electron'
// 触发监听事件
ipcRenderer.send('show-context-menu')

调用

好像还没说怎么调用呢,当然是那个右键触发打开上下文菜单啦不过这个应该不用说吧

右键事件为contextmenu,vue中可以直接在标签上@contextmenu.prevent=""即可