Electron原生選單

依韻_宵音發表於2021-12-10

Electron 中可以使用html來開發其中展示的內容,一些選單也可以以html的形式來繪製,點選時呼叫相關api即可,雖然構建方便,樣式可任意調整。但其實際是模擬的選單,並非應用原生的選單。這種模擬的選單有如下不足:

  • html模擬生成,非原生。
  • 每個功能均需自行程式碼呼叫或實現,而實際原生選單有很多預設行為可直接使用。
  • Mac 和 Linux 中模擬的選單無法顯示到最上方的選單欄中去。
  • html 模擬選單無法生成系統托盤的選單。

下面將介紹一下 Electron 中的原生選單。

選單型別

在 Electron 中有三種型別的選單:應用選單、上下文選單及托盤選單。

應用選單

應用選單即應用上方的那一條選單。

構建選單隻需要一個陣列即可,其中每個成員即為一個選單項,每個選單項均有一些指定的配置。以如下程式碼為例:

const myMenuTemplate = [
  {
    // 設定選單項文字
    label: '檔案',
    // 設定子選單
    submenu: [
      {
        label: '關於 Electron',
        // 設定選單角色
        role: 'about', // about (關於),此值只針對 Mac  OS X 系統
        // 點選事件 role 屬效能識別時 點選事件無效
        click: () => {
          var aboutWin = new BrowserWindow({ width: 300, height: 200, parent: win, modal: true });
          aboutWin.loadFile('about.html');
        }
      },
      {
        // 設定選單的型別是分隔欄
        type: 'separator'
      },
      {
        label: '關閉',
        // 設定選單的熱鍵
        accelerator: 'Command+Q',
        click: () => {
          win.close();
        }
      }
    ]
  },
  {
    label: '編輯',
    submenu: [
      {
        label: '複製',
        click: () => {
          win.webContents.insertText('複製');
        }
      },
      {
        label: '剪下',
        click: () => {
          win.webContents.insertText('剪下');
        }
      },
      {
        type: 'separator'
      },
      {
        label: '查詢',
        accelerator: 'Command+F',
        click: () => {
          win.webContents.insertText('查詢');
        }
      },
      {
        label: '替換',
        accelerator: 'Command+R',
        click: () => {
          win.webContents.insertText('替換');
        }
      }
    ]
  }
];

以上就是一個選單的配置,常用的有如下配置:

  • id 可選,指定選單的id,後續如需使用可直接通過id獲取。
  • type 選單型別,可選值 normalseparatorsubmenucheckboxradio
  • label 用於配置選單上顯示的文字。
  • click 選單點選處理函式。
  • checked 是否已經勾選 ,僅對型別為 checkbox 或 radio 的選單項有效。
  • accelerator 此選單對應的快捷鍵。
  • icon 選單專案上的圖示。需特別注意,圖示不會自動縮放,需提供合適大小圖片,相容高 DPI 裝置需按照命名規範提供圖示,參考高解析度
  • role 指此選單的一些系統預定義行為,如 複製、貼上、最小化、最大化等,值系統可識別時,配置的點選事件將會無效。此配置的值在 Mac 下有更多的支援,具體可參考選單角色

更多選單專案的配置可以參考 選單項

要應用選單,必須要使用 Menu 類,其定義放在 electron 名稱空間下。 Menu 類有以下兩個靜態方法,用於生成並應用選單

  • buildFromTemplate(menuTpl /* menu 選單配置 */) 用來根據選單配置生成選單例項,返回值為選單物件,可替換為 new Menu()
  • setApplicationMenu(menu /* 選單物件 */) 方法將其作為應用選單。

載入檔案並應用選單程式碼如下:

const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
const Menu = electron.Menu;

function createWindow() {
  win = new BrowserWindow({ file: 'index.html' });
  win.loadFile('./index.html');
  // 應用上面準備好的選單配置生成
  const template = myMenuTemplate;
  //  建立選單物件
  const menu = Menu.buildFromTemplate(template);
  //  設定應用選單
  Menu.setApplicationMenu(menu);
  win.on('closed', () => {
    console.log('closed');
    win = null;
  });
}
app.on('ready', createWindow);
app.on('activate', () => {
  if (win === null) {
    createWindow();
  }
});

基於以上程式碼,window下可以看到如下效果:

43385-uicw6dsf0r.png

59942-hz1loyr540c.png

Mac 下是如下效果:

39324-03jzp4pdn385.png

08127-2spol8owt9g.png

window下我們自定義的關於效果:

52577-h8kngdc6u8r.png

而 Mac 下about直接由系統提供:

31156-n5mu3vo79ad.png

效果圖

很明顯, 在 window 下正如配置的樣子,而 Mac 上卻有明顯不同,第一個檔案選單不見了,編輯裡面又多了兩個選單專案。

這是 Mac 系統本身的特性,其中第一個選單在 Mac 下的 文字顯示必然是應用的名稱,此處是以 electron 命令啟動的所以是 electron 。可以理解為 Mac 下第一個選單項配置 label 是無效的。(想想看你的 Mac 第一個選單大多數都是應用的名稱,如 Safri 、 PhotoShop CC)

如果你就是有強迫症,一定要改這個需修改應用程式包的 Info.plist 檔案,請參考 About Information Property List Files

以上即為預設配置應用選單的形式,不過在實際場景中經常還會有動態調整選單的需求,如在某些狀態下某個選單不可用,進入某種狀態時多一個選單,此時我們需要能夠調整選單專案的可用性或可見性並提供動態新增選單的能力。

有如下相關配置可調整選單項的狀態:

  • menuItem.enabled 布林值標識選單項是否啟用該項。
  • menuItem.visible 布林值標識選單項是否可見。
  • menuItem.checked 布林值標識選單項是否選中該項。

獲取選單項可以使用選單物件上的 getMenuItemById(id) 方法,此方法將返回對應的選單項,對選單項的相關屬性進行調整即可。

新增選單專案,可以先使用 new MenuItem() 構建一個選單項,然呼叫選單例項的如下方法進行插入:

  • menu.append(menuItem) 在選單中新增一個選單。
  • menu.insert(pos, menuItem) 在選單中的指定位置新增一個新選單項

windows下依次點選切換顯示和切換啟用效果如下:

28059-gvpbyjh1s58.png

新增效果如下:

72478-tkf3y5rsupa.png

mac 中切換和新增效果:

98518-hoifqg0fy5.png

上下文選單

上下文選單即滑鼠右鍵選單,構建選單的方式還是和上面應用選單中講到的方式一樣,通過選單項的配置陣列來生成。不過使之成為上下文選單不再需要使用 setApplicationMenu() 方法,僅需構建好選單,然後監聽 contextmenu 事件,呼叫 popup({x,y}) 在指定位置顯示選單即可。

不完整程式碼示例如下:

const menu = new Menu( /* 選單配置陣列*/ );
document.getElementById('panel').addEventListener('contextmenu', (ev) => {
  event.preventDefault();
  const {x, y} = ev;
  //  彈出上下文選單
  menu.popup({x, y});
  return false;
});

當在某種情況下需要關閉上下選單時,僅需呼叫選單物件的 colsePopup(browserWindow) 方法即可。如果應用涉及多視窗,需關閉其他視窗的上下文選單時,可將此視窗作為引數傳入即可,預設是操作當前視窗。

其餘的地方和應用選單完全相同。

托盤選單

托盤選單即window中右下角點選時的選單,mac 上為右上方應用小圖示點選的選單。

不過預設應用是不會在托盤中顯示的,如需顯示,需要使用 Electron 中的 Tray 類來建立。

以如下演示程式碼即可建立托盤圖示,並關聯點選的托盤選單。

const {app, Menu, Tray, BrowserWindow} = require('electron')
let tray;
let contextMenu;

function createWindow() {
  win = new BrowserWindow({
    file: 'index.html'
  });
  win.loadFile('./index.html');
  //  建立 Tray 物件,並指定托盤圖示
  tray = new Tray('/images/tray.png');
  //  建立用於托盤圖示的上下文選單
  contextMenu = Menu.buildFromTemplate([{
      label: '複製',
      role: 'copy'
    },
    {
      label: '剪下',
      role: 'cut'
    },
    {
      label: '貼上',
      role: 'paste'
    }
  ]);
  //  設定托盤圖示的提示文字
  tray.setToolTip('這是Electron的應用托盤圖示')
  //  將托盤圖示與上下文選單關聯
  tray.setContextMenu(contextMenu)
  win.on('closed', () => {
    tray.destroy();
    win = null;
  });
}

app.on('ready', createWindow)
app.on('activate', () => {
  if (win === null) {
    createWindow();
  }
});

關鍵操作說明如下:

  1. 使用 new Tray(image) 來建立應用托盤。
  2. 使用 setToolTip(toolTip) 為托盤新增 toolTip 。
  3. 配置選單,並使用 setContextMenu 將選單和托盤關聯, 這一步是必須操作,托盤圖示必須具備上下文選單時才會展示

演示效果如下:

windows 中效果:

93771-9tyb2dsfxts.png

Mac 中:

46860-n7cfzl73yo.png

關於系統托盤 Tray 的更說明和請參考官方文件 系統托盤

不同系統中互動不同的解決方案:

在windows中直接點選應用托盤是啟用當前應用,右鍵點選才是展示托盤選單。而 Mac 中通常左鍵點選即為展示托盤選單,如果你需要你的應用在各個平臺下均以有相同的互動方式,可手動使用程式碼進行調整。涉及如下幾個事件和方法:

  • click 托盤單擊時觸發
  • right-click 托盤右鍵點選時觸發
  • tray.popUpContextMenu([menu, position]) 彈出托盤圖示的上下文選單。如果傳入了 menu 引數,將會彈出 menu 而不是托盤圖示的上下文選單,引數 position 只在 Windows 上可用, 並擁有預設值 (0, 0)

windows 的系統托盤的氣泡通知

應用托盤在 windows 系統中有一個非常有用且常見的功能——氣泡通知,僅需使用托盤的 displayBalloon() 方法即可,演示如下:

tray.displayBalloon({
  // icon: './images/icon.png', // 通知的圖示 (可選) 
  title: '氣泡通知標題',
  content: '氣泡通知的內容'
});
tray.on('balloon-show', () => {
  console.log('氣泡通知顯示');
});
//  新增氣泡訊息單擊事件
tray.on('balloon-click', () => {
  console.log('氣泡通知被使用者點選');
});
//  新增氣泡訊息關閉事件
tray.on('balloon-closed', () => {
  console.log('氣泡通自動關閉');
});

氣泡通知還具備點選的功能,因此係統托盤還具備如下事件:

  • balloon-show ,當氣泡訊息顯示時觸發;
  • balloon-click ,當單擊氣泡訊息時觸發;
  • balloon-closed ,當氣泡訊息關閉時觸發。

需注意的是:balloon-click 和 balloon-closed 是互斥的,兩者僅會觸發其中一個:單擊氣泡訊息後,氣泡訊息會立刻關閉,在這種情況下,並不會觸發 balloon-closed 事件;balloon-closed 事件僅在氣泡訊息顯示幾秒後自動關閉的情況下觸發。

效果圖如下:

40015-7qu5j9xe54i.png

16358-vk3qkgsjpe.png

以上就是 Electron 原生選單常用的使用方法說明,想要了解更深入的內容請參考如下內容:

相關文章