导语:近几年,随着 Electron/ NW.js 等技术的兴起,也催生了一批优秀的桌面端开发者工具,好比 VSCode、微信开发者工具、飞冰(ICE) 等等。对于开发者而言,桌面端开发者工具的优点是:可视化能力、操做系统层面的 API 访问、和良好的开发调试体验。所以,最近准备系统性的深刻学习下 Electron 技术而且将学习的知识进行适当沉淀。本篇文章主要总结 Electron 的自定义菜单。git
传统的 Web APP 的开发基本上不会涉及到菜单,可是在 Electron 里面它提供了对于菜单全面的控制,你能够经过 Menu、MenuItem 模块来建立应用所需的自定义菜单。这篇文章咱们一块儿探讨下 Electron 中有哪些菜单种类,又是如何经过代码去自定义菜单的?github
首先,咱们一块儿看看基本的菜单介绍,方便你们对于基本的概念有初步的认识。api
Electron 里的菜单大致上分为三类:应用菜单、上下文菜单和 Dock 菜单(仅针对 OSX 系统)。数组
这里以微信开发者工具为例(微信开发者工具基于 NW.js 进行开发,主要出于 Windows XP兼容性考虑),来分别介绍这几种菜单的含义。打开微信开发者工具,能够经过下图,很清晰的发现3个菜单所处的位置。缓存
这三种菜单的含义分别是:bash
了解了菜单的基本概念后,接下来咱们一块儿看看如何经过代码去实现自定义菜单的功能。微信
首先看看应用菜单,Electron 默认会有一个标准的应用菜单,咱们一块儿看看默认的应用菜单效果:微信开发
仔细分析下默认应用菜单包括的菜单结构以下:app
若是你但愿定制应用菜单,你须要自行实现整个菜单的定义。这里须要注意,应用菜单只能在 Electron 的主进程中进行访问。例如:electron
// main.js
const {
app,
Menu
} = require('electron');
app.on('ready', () => {
const appMenu = Menu.buildFromTemplate(menuTemplate);
Menu.setApplicationMenu(appMenu);
});
复制代码
这里面重点关注 app 的 ready 这段代码块,应用菜单经过 **Menu.setApplicationMenu **进行设置。接下来分别从菜单模板、分隔符、快捷键和子菜单几个方面来系统介绍下应用菜单的内容。
菜单的 template 是一个对象数组,每一个对象会定义一个独立的菜单,它会显示在应用菜单的 Bar 位置,显示的文字经过 label 属性进行定义。
以这段代码为例,咱们定义了两个菜单,每一个菜单都包含两个菜单项,菜单项就是咱们点击菜单时下拉出来的内容。
const template = [
{
label: 'Edit App',
submenu: [
{
label: 'Undo'
},
{
label: 'Redo'
}
]
},
{
label: 'View App',
submenu: [
{
label: 'Reload'
},
{
label: 'Toggle Full Screen'
}
]
}
];
复制代码
对应的效果:
这里值得注意的是:对于 OSX 而言,应用菜单的第一个菜单项是应用程序的名字,会使得 Edit App 这个菜单被覆盖掉。所以,咱们须要针对 OSX 进行特殊处理,处理的过程一般是:
if (process.platform === 'darwin') {
template.unshift({
label: app.getName(),
submenu: [
{
label: 'Quit',
accelerator: 'CmdOrCtrl+Q',
click() {
app.quit();
}
}
]
});
}
复制代码
经过 type: 'separator' 能够在两个菜单项之间定义一个分隔符,分隔符的做用主要是将功能类似的菜单项分隔在一块儿,便于更好的操做。
const template = [
{
label: 'Edit App',
submenu: [
{
label: 'Undo'
},
{
type: 'separator'
},
{
label: 'Redo'
}
]
}
];
复制代码
能够看到,Undo 和 Redo 之间出现了一个分隔符。
接下来,咱们一块儿了解下经常使用的快捷键和内置的 role 功能。
快捷键咱们平常开发过程当中用得不少,好比 Ctrl + A 全选,Ctrl + C 复制,Ctrl + V 粘贴。能够供咱们选择的快捷键有:
咱们把上面的代码修改一下,增长快捷键,快捷键经过 accelerator 属性进行定义。
const template = [
{
label: 'Edit App',
submenu: [
{
label: 'Undo',
accelerator: 'CmdOrCtrl+Z'
},
{
type: 'separator'
},
{
label: 'Redo',
accelerator: 'Shift+CmdOrCtrl+Z',
}
]
}
];
复制代码
添加完快捷键后,可能你会问,点击某个菜单或者某个快捷键后如何触发相应的逻辑呢?这个能够经过编写 click() 自定义回调函数或者使用 Electron 内置的 role 进行指定。咱们将上述代码继续修改:
const template = [
{
label: 'Edit App',
submenu: [
{
label: 'Undo',
accelerator: 'CmdOrCtrl+Z',
role: 'undo'
},
{
type: 'separator'
},
{
label: 'Redo',
accelerator: 'Shift+CmdOrCtrl+Z',
role: 'redo'
}
]
}
];
复制代码
增长了 role 以后能够发现就有对应的操做效果了,Electron 的全部内置的 role 以下:
完整的 Role 能够查看:electronjs.org/docs/api/me…
咱们在前面的基础上增长一个新的菜单 Sub Menu,能够看到这个菜单里面的菜单项新增了 submenu 属性,经过这个属性能够继续定义子菜单,此处咱们定义了 Submenu item1 和 Submenu item2。
const template = [
{
label: 'Edit App',
submenu: [
{
label: 'Undo',
accelerator: 'CmdOrCtrl+Z',
role: 'undo'
},
{
type: 'separator'
},
{
label: 'Redo',
accelerator: 'Shift+CmdOrCtrl+Z',
role: 'redo'
}
]
},
{
label: 'Sub Menu',
submenu: [
{
label: 'Submenu item',
submenu: [
{
label: 'Submenu item1'
},
{
label: 'Submenu item2'
}
]
}
]
},
];
复制代码
子菜单的效果以下:
到这里,应用菜单这个最重要的内容就介绍完了,接下来咱们看看上下文菜单这个部分。
上下文菜单(context menu)就是咱们一般说的右键菜单,文章开头有展现效果。须要注意的是:上下文菜单,须要在渲染进程中进行实现。在渲染进程中是须要经过remote模块调用主进程中的模块。
实现上下文菜单很简单,只须要监听到 contextmenu 事件,而后将菜单展现出来便可。
//renderer.js
const { remote } = require('electron');
const { Menu } = remote;
const createContextMenu = () => {
const contextTemplate = [
{
label: 'Cut',
role: 'cut'
},
{
label: 'Copy',
role: 'copy'
}
];
const contextMenu = Menu.buildFromTemplate(contextTemplate);
return contextMenu;
}
window.addEventListener('contextmenu', (event) => {
event.preventDefault();
const contextMenu = createContextMenu();
contextMenu.popup({
window: remote.getCurrentWindow()
});
}, false);
复制代码
最后,咱们一块儿看看 Dock 菜单,Dock 的菜单实现也是在主进程中,实现思路和前面基本相似,核心是经过 app.dock.setMenu 这个 API 进行实现的。
// main.js
const createDockMenu = () => {
const dockTempalte = [
{
label: 'New Window',
click () {
console.log('New Window');
}
}, {
label: 'New Window with Settings',
submenu: [
{ label: 'Basic' },
{ label: 'Pro' }
]
},
{
label: 'New Command...'
}
];
const dockMenu = Menu.buildFromTemplate(dockTempalte);
app.dock.setMenu(dockMenu);
}
app.on('ready', function() {
createDockMenu();
});
复制代码
Dock 菜单的效果以下:
至此,这篇文章到这里就结束了,感谢您的阅读。后面的文章会涉及到对话框、 IPC 通讯、Electron 应用的测试、打包、发布和自动更新等内容。
个人我的博客:github.com/cpselvis/bl…
想学习更多干货内容能够扫码关注个人公众号:推送频率每周一篇