導語:近幾年,隨着 Electron/ NW.js 等技術的興起,也催生了一批優秀的桌面端開發者工具,好比 VSCode、微信開發者工具、飛冰(ICE) 等等。對於開發者而言,桌面端開發者工具的優點是:可視化能力、操做系統層面的 API 訪問、和良好的開發調試體驗。所以,最近準備系統性的深刻學習下 Electron 技術而且將學習的知識進行適當沉澱。本篇文章主要總結 Electron 的自定義菜單。
傳統的 Web APP 的開發基本上不會涉及到菜單,可是在 Electron 裏面它提供了對於菜單全面的控制,你能夠經過 Menu、MenuItem 模塊來建立應用所需的自定義菜單。這篇文章咱們一塊兒探討下 Electron 中有哪些菜單種類,又是如何經過代碼去自定義菜單的?git
首先,咱們一塊兒看看基本的菜單介紹,方便你們對於基本的概念有初步的認識。github
Electron 裏的菜單大致上分爲三類:應用菜單、上下文菜單和 Dock 菜單(僅針對 OSX 系統)。api
這裏以微信開發者工具爲例(微信開發者工具基於 NW.js 進行開發,主要出於 Windows XP兼容性考慮),來分別介紹這幾種菜單的含義。打開微信開發者工具,能夠經過下圖,很清晰的發現3個菜單所處的位置。數組
這三種菜單的含義分別是:緩存
瞭解了菜單的基本概念後,接下來咱們一塊兒看看如何經過代碼去實現自定義菜單的功能。微信
首先看看應用菜單,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 能夠查看:https://electronjs.org/docs/api/menu-item#roles
咱們在前面的基礎上增長一個新的菜單 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 應用的測試、打包、發佈和自動更新等內容。
個人我的博客:https://github.com/cpselvis/b...
想學習更多幹貨內容能夠掃碼關注個人公衆號:推送頻率每週一篇