天天看點

使用JS開發桌面端應用程式NW.js-1-Menu菜單的使用小記

前言

本文主要内容為nw.js官方文檔中沒有提到,而在實際入手開發過程中才碰到的問題以及經驗的彙總。

詳情請檢視官方文檔:http://docs.nwjs.io/en/latest/References/Menu/

1. MenuStrip與ContextMenu

在聊nwjs中的Menu之前先說下在傳統window桌面端應用開發中的兩種常見的菜單。

windows中的MenuStrip

第一種:MenuStrip,菜單欄,通常在主窗體中的頂部,橫向展示。如圖:

使用JS開發桌面端應用程式NW.js-1-Menu菜單的使用小記

windows中的ContextMenu

第二種:ContextMenu,上下文菜單,也就是右鍵菜單,關聯某個元素,再某個元素上點選右鍵展現的菜單

使用JS開發桌面端應用程式NW.js-1-Menu菜單的使用小記

nw.js中的nw.Menu

而在nw.js中,将windows系統的這兩種菜單結合成一個對象:

nw.Menu

而區分的方法在于構造的配置對象的

type

屬性。

  1. type屬性設定為"menubar"則展現為MenuStrip行為,即窗體頂部菜單欄。
  2. type屬性設定為"contextmenu"則展現為右鍵菜單行為。預設為右鍵菜單

官方說明:

/**
* Object that contains options to use while creation of nw.Menu. example: new nw.Menu(MenuOption)
*/
interface MenuOption {
   /**
    * {string} (Optional) two types are accepted by this method: "menubar" or "contextmenu". The value is set to "contextmenu" by default.
    */
   type: string;
}
           

2. nwjs中的多級菜單結構組成

在nwjs中,有關菜單的隻有兩個對象,

nw.Menu

nw.MenuItem

。其中nw.Menu更多的功能與行為應該稱之為 菜單集合。而 nw.MenuItem才是真正的 菜單項。

用一張圖來描述Menu和MenuItem對應的實際結構如圖:

使用JS開發桌面端應用程式NW.js-1-Menu菜單的使用小記

如上圖,紅框為Menu,橙色為MenuItem,所有MenuItem的集合均為Menu,而MenuItem的子集的類型為Menu。

接下來建立一個上圖中的頂部菜單欄的代碼示例:

//建立一個頂部菜單欄,類型為:menubar
var menuBar = new nw.Menu({
  type: 'menubar'
});

//建立一個一級菜單項-檔案
var fileMenu = new nw.MenuItem({
  label: "檔案",
});

//檔案菜單的子菜單集合,類型為:contextmenu
var fileMenuColl = new nw.Menu({ type: "contextmenu" });
//設定一級菜單檔案的子菜單
fileMenu.submenu = fileMenuColl;


// 建立一級菜單檔案的子菜單:打開
var openMenu = new nw.MenuItem({
  label: "打開",
  click: function () {
      console.log("打開");
  },
});
//将打開菜單項 添加入檔案子菜單集合中
fileMenuColl.append(openMenu);


//建立一級菜單檔案的子菜單:資料總管
var explorerMenu = new nw.MenuItem({
  label: "資料總管",
  click: function () {
      console.log("資料總管");
  },
});
fileMenuColl.append(explorerMenu);

//最後将一級菜單項檔案 添加入菜單欄
menuBar.append(fileMenu);

//設定窗體菜單欄
nw.Window.get().menu = menuBar;
           

效果如下:

使用JS開發桌面端應用程式NW.js-1-Menu菜單的使用小記

3. MenItem必須最後再被Menu.append添加

問題見代碼示例。

如将上述代碼化簡後:

var menuBar = new nw.Menu({ type: 'menubar' });
var fileMenu = new nw.MenuItem({ label: "一級菜單" });

var fileMenuColl = new nw.Menu();
fileMenu.submenu = fileMenuColl;
var openMenu = new nw.MenuItem({ label: "二級菜單" });
fileMenuColl.append(openMenu);

menuBar.append(fileMenu);//關鍵,放在最後沒問題,正常!

win.menu = menuBar;
           
使用JS開發桌面端應用程式NW.js-1-Menu菜單的使用小記

但是如果将

menuBar.append(fileMenu)

放在剛剛建立完

fileMenu

之後的話:

var menuBar = new nw.Menu({ type: 'menubar' });
var fileMenu = new nw.MenuItem({ label: "一級菜單" });
//關鍵,建立fileMenu後立刻添加入菜單欄,會發生無法顯示二級菜單的問題!!!
menuBar.append(fileMenu);

var fileMenuColl = new nw.Menu();
fileMenu.submenu = fileMenuColl;
var openMenu = new nw.MenuItem({ label: "二級菜單" });
fileMenuColl.append(openMenu);

win.menu = menuBar;
           

問題:會出現二級菜單無法打開,隻能看到一級菜單的問題。

另外,如果再建立fileMenu時直接在構造函數的配置對象中制定了submenu的話,也可以避規此問題。

私以為這個應該屬于nwjs的一個bug或是一個缺陷。理論上來講都屬性引用類型,先append再新增,或先新增再append應該都是可以的。至少在C#的WinForm開發菜單時是這樣的。

原因不明。

解決方案:隻能在開發過程中嚴格遵守: 所有級别的菜單項,必須全部建立完成後最後再被父級append。

4. nwjs頂部菜單欄不支援純一級菜單

在windows應用程式中:

頂部菜單欄可以隻有一級菜單,而沒有其下屬二級菜單。沒有二級菜單也可實作相應各個點選事件等等,不強制要求必須有二級菜單。

而在nwjs中:

頂部菜單欄的純一級菜單,即沒有二級菜單項的一級菜單無法響應點選事件,其設定的click事件也是無效的,必須在二級菜單及更進階别的菜單中才可以響應點選事件。

這就帶來一個問題:

在把純windows應用程式使用nwjs重寫時,那些純一級菜單就必須折疊到二級菜單中,才能使用。

另外:

nwjs中隻有頂部菜單受此影響,右鍵菜單不受此影響。

這一點官方也有說明:

To create a menubar, usually you have to create a 2-level menu and assign it to win.menu

要建立一個窗體頂部菜單欄,必須使用二級菜單,并指派給win.menu

http://docs.nwjs.io/en/latest/References/Menu/#synopsis

個人猜測:

nwjs隻是以這樣做是因為在mac OS系統中,似乎不支援純一級菜單項。是以nwjs為了要相容三方平台,統一行為,是以屏蔽了菜單欄的純一級菜單項的點選功能,讓其不具有實際功能,隻能打開二級菜單欄。

5. 關于MenuItem

關于type屬性

MenuItem菜單項有三種類型

normal

checkbox

separator

normal

:标準模式,也是預設模式,純文字菜單項。

checkbox

:可選中的菜單項,前面會有一個對勾,重複點選狀态來回切換。

separator

:分割菜單項,展現為一條直線分隔符。

示例代碼:

var reloadMenu = new nw.MenuItem({
    label: "重新整理",
    type: "normal",
});

var separatorMenu = new nw.MenuItem({
    type: "separator"
});

var checkMenu = new nw.MenuItem({
    type: "checkbox",
    label: "是否展現縮略圖"
});

var exitMenu = new nw.MenuItem({
    label: "退出",
});
           
使用JS開發桌面端應用程式NW.js-1-Menu菜單的使用小記

另外:MenuItem的type屬性隻能在建立時設定,不能在運作時動态更改。

key屬性不支援菜單欄形式下的一級菜單

在windows系統中:

菜單欄中的文字後面的括号下劃線英文,是展開此菜單欄的快捷鍵,方式是

ALT+對應英文字母

如下圖,展開檔案菜單的快捷鍵是

ALT+F

,執行檔案菜單中的關閉菜單項的快捷鍵是

ALT+C

使用JS開發桌面端應用程式NW.js-1-Menu菜單的使用小記

在nwjs中:

也提供了類似的功能,是MenuItem的

key

屬性和

modifiers

key

屬性用來設定觸發的快捷鍵。

modifiers

屬性用來設定跟快捷鍵相關聯的修飾鍵。

如我們要設定菜單項

重新整理

的快捷鍵為

F5

則可以:

var reloadMenu = new nw.MenuItem({
    label: "重新整理",
    key: "F5",
    click: function () {
        pageWindow.location.reload();
    },
});
           

如要設定為快捷鍵為

ALT+R

var reloadMenu = new nw.MenuItem({
    label: "重新整理",
    key: "r",
    modifiers:"alt",
    click: function () {
        pageWindow.location.reload();
    },
});
           

展現效果為:

使用JS開發桌面端應用程式NW.js-1-Menu菜單的使用小記

nwjs的問題在于:

nwjs中不支援設定菜單欄的一級菜單的快捷鍵。

也就是無論如何設定,一級菜單都不會相應快捷鍵自動彈出顯示。無法實作windows系統中的效果。隻有二級菜單及以下才生效。

如果給一個含有三級菜單的二級菜單設定快捷鍵,也就是給一個包含子集展開項設定了快捷鍵,其行為也不會像windows系統中那樣展開他的下屬菜單集合,而是直接執行目前它本身的

click

事件。

//重新整理菜單的下屬子集
var reloadMenuColl = new nw.Menu();
reloadMenuColl.append(new nw.MenuItem({ label: "重新整理二級" }));

/** 操作-重新整理 */
var reloadMenu = new nw.MenuItem({
    label: "重新整理",
    key: "r",
    modifiers: "alt",
    click: function () {
        pageWindow.location.reload();
    },
    submenu: reloadMenuColl
});
           

如圖:

使用JS開發桌面端應用程式NW.js-1-Menu菜單的使用小記

按下快捷鍵

ALT+R

,直接重新整理了頁面,而沒有展開二級菜單。但如果用滑鼠點選那個

重新整理

菜單的話,是無論如何也不會觸發重新整理操作的。但通過快捷鍵反倒可以...

有關這一點nwjs的官方文檔中并沒有特殊說明,我姑且認定為沒有太大影響的缺陷吧。詳見:http://docs.nwjs.io/en/latest/References/MenuItem/

源代碼下載下傳

本文上述源代碼已托管至Github:

https://github.com/xxcanghai/nwjs-demo/tree/master/menu

歡迎Start & Follow~

後記

以上為nw.js入坑兩周來的有關菜單開發的小記。因為我們要相容XP系統,是以沒得選,隻能用nw.js。其github上的issue區也是紅紅火火,隻能說感覺nw在很多功能細節上還需打磨和完善。

如果您認為本文對得起您所閱讀他所花的時間,歡迎點選右下角↘ 推薦。您的支援是我繼續寫作最大的動力,謝謝

作者:小小滄海

出處:http://www.cnblogs.com/xxcanghai/

本文位址:http://www.cnblogs.com/xxcanghai/

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。