這一節主要說一下Menu對鍵盤的支援,本來不支援鍵盤這個菜單也完全可用了,不過還是為了和WinForm的Menu統一,是以支援了和WinForm菜單一樣的操作方式。
菜單的處理函數Menu.prototype.Keydown是在AttachEvents()方法裡通過:
doc.attachEvent('onkeydown', this.Keydown);
來attach的,為什麼要使用onkeydown不用onkeypress呢?是為了讓菜單通過鍵盤快捷鍵來彈出子菜單時和WinForm方式菜單一樣。這個doc是該菜單的popup視窗的doucment對象。
下面一邊看代碼一邊講吧:
if ( !evt || !evt.srcElement )
{
return;
}
var menuBody = evt.srcElement;
var menuHtml = FindChildElement(menuBody, 'TABLE');
if ( !menuHtml || !menuHtml.uniqueId )
menuHtml = FindParentElement(menuBody, 'TABLE');
if ( !menuHtml || !menuHtml.uniqueId )
{
return;
}
var menuObj = __MenuCache__[menuHtml.uniqueId];
if ( menuObj.HasSubMenuExpanded() )
由于onkeydown事件處理函數attach在document上,是以要得到菜單必須尋找body裡面的Table
element,不過這個evt.srcElement可能是body,也可能是table的裡的元素,關鍵是看當時菜單popup裡的焦點在那個element上。上面代碼的最後4句話是判斷響應onkeydown事件的菜單是否有子菜單expanded,因為我們隻讓最後一級顯示的子菜單處理keystroke,父級的必須忽略,否則就亂套了。
if ( menuObj.m_ShowTimer )
window.clearTimeout(menuObj.m_ShowTimer);
menuObj.m_ShowTimer = null;
這是用來支援子菜單顯示特效的一個timer,如果手動顯示子菜單(包括滑鼠click和鍵盤快捷鍵),清除這個timer。
var activeIndex = -1;
for ( var i=0 ; i < menuObj.m_Items.length ; ++i )
if ( menuObj.m_ActiveItem == menuObj.m_Items[i] )
activeIndex = i;
break;
把菜單中已active的item的index搜尋出來,沒有active的menuitem,index為-1。
var sign = -1;
switch( evt.keyCode )
case 37 : // left
if ( menuObj.m_ParentMenu )
{
menuObj.Hide();
}
case 38 : // up | no break;
sign = 1;
if ( activeIndex == -1 )
activeIndex = 0;
case 40 : // down
var itemCount = menuObj.m_Items.length;
for ( var i=1 ; i <= itemCount ; ++i )
var index = (itemCount+activeIndex-i*sign)%itemCount;
var item = menuObj.m_Items[index];
if ( !item.m_Disabled && item.m_Text != '-' )
{
menuObj.__resumeItem();
menuObj.m_ActiveItem = item;
menuObj.__activeItem();
break;
}
case 39 : // right | no break;
var activeItem = menuObj.m_ActiveItem;
if ( !activeItem || !activeItem.m_ChildMenu )
break;
case 13 : // enter
menuObj.Click();
case 27 :
處理left, right, up, down四個鍵,up和down要麻煩些,因為要查找可用的(separator
item和disabled
item是不可用的,不能被active)下一個itme來active,到了最有一條itme再同方向up或down還需要有輪轉的效果。
HACK: 由于up和down的代碼完全相同,隻是搜尋方向不同,是以用了一個sign(取值1|-1)标志來判斷搜尋方向。
if ( evt.keyCode >= 48 && evt.keyCode <= 90 )
var keyList = '';
var key = String.fromCharCode(evt.keyCode);
for ( var i=0 ; i < menuObj.m_Items.length ; ++i )
var item = menuObj.m_Items[i];
if ( !item.m_Disabled && item.m_Mnemonic )
{
keyList += item.m_Mnemonic;
else
keyList += '-';
var index = keyList.indexOf(key);
if ( index != -1 )
{
if ( keyList.indexOf(key) == keyList.lastIndexOf(key) )
if ( !menuObj.m_Items[index].m_Disabled )
menuObj.__resumeItem();
menuObj.m_ActiveItem = menuObj.m_Items[index];
menuObj.Click();
menuObj.__resumeItem();
var newActive;
if ( !evt.shiftKey )
newActive = keyList.indexOf(key, activeIndex+1);
else
if ( activeIndex == 0 )
{
newActive = -1;
index = keyList.lastIndexOf(key);
}
else
newActive = keyList.lastIndexOf(key, activeIndex-1);
if ( newActive == -1 )
menuObj.m_ActiveItem = menuObj.m_Items[newActive];
menuObj.__activeItem();
處理菜單條目上的快捷鍵Mnemonic,這裡的算法是這樣的,把該菜單上的每個item上的Mnemonic字元取出組成一個字元串,沒有Mnemonic就用'-'代替。比如下面的菜單的Mnemonic字元組成的字元串分别是:
第一級:"--N---",第二級:"M",第三級:"TTTT"。然後使用String.indexOf(key)就取到被按快捷鍵的MenuItem的index了,由于沒有限制同一個Menu裡面多個MenuItem具有相同的Mnemonic,是以像第三級菜單,一直按T鍵的效果就和按down
key一樣,它的效果使用語句Sting.indexOf(key, activeIndex+1)來獲得。
#region 附Menu.prototype.Keydown = function(evt)代碼
Menu.prototype.Keydown = function(evt)
{
if ( evt.keyCode != 27 )
{
evt.returnValue = null;
evt.cancelBubble = true;
};
本文轉自部落格園鳥食軒的部落格,原文連結:http://www.cnblogs.com/birdshome/,如需轉載請自行聯系原部落客。