如圖例:
此菜單跟之前提供的outlook菜單一樣來自於sitemap設置
由於菜單是放在FrameSet中的一個frame上,因此彈出的子菜單不能用DIV的方式來實現,而是採用window.createpopup()的方式彈出一個窗口,並且在窗口中輸出HTML來實現菜單內容的展現和行爲.
採用此方法用到的基本知識點:
彈出窗口:
var oPopup= window.createPopup();
oPopup.innerHTML = "";
oPopup.document.write(sHTML); //寫入輸出內容
oPopup.show(left,top,width,height,document.body);
隱藏窗口:
oPopup.hide();
採用createpopup的方式來實現無限級別的彈出菜單需要注意以下細節和設計技巧:
1. 一個window同時只能彈出一個窗口,彈出另一個窗口的時候之前的窗口會自動關閉.
解決思路: E8.Net中菜單輸出的腳本爲一個類文件,類中設置了一個數組對象,保存每一級窗口創建的createpopup,用數組方式保存,在不同級別的彈出時用到對應窗口位置的彈出對象.
oPopup=E8MenuConfig.WindowsList[deep]; //deep爲深度
if(null==oPopup)
{
oPopup=obj.document.parentWindow.window.createPopup();
}
這樣可以保證每一級菜單彈出窗口不受影響
2.如何計算彈出窗口的位置,會遇到上級菜單已經靠近屏幕的情況.
解決思路:由於彈出窗口的位置是相對位置,需要考慮到相對屏幕有效位置的計算參考,把最上一級相對屏幕寬度(screen.availWidth)的計算結果帶入到遞歸調用中去,無論哪一級的菜單均可比較到屏幕相對寬度(screen.availWidth)
if(deep > 1)
{
left += obj.offsetWidth - 3;
//如果到了屏幕的右邊,則從左邊開始
if(topLeft + width * 2 > screen.availWidth)
{
left = left - obj.offsetWidth - width + 3;
}
}
3.如何設計無限級菜單的數據源已保證遞歸調用的可行性.
解決思路:菜單採用2維數組作爲數據源,由於不知道可能會產生的層次數量,需要採用遞歸調用中根據一個參數不同執行相同的代碼能找到當前彈出窗口內容.
數組參考:
arrOperateMenu: MenuCode, SupMenuCode, MenuName, MenuUrl, Level, HasChild
menuCode 和SupMenuCode 爲父子關係鏈接,彈出窗口函數 以SupMenucode爲入口,下一級以MenuCode參數爲入口,保證到循環的可行性
</script><script language="javascript">
var arrOperateMenu = new Array();
.
arrOperateMenu[17] = new Array("50202", "502", "常用類別管理", "/NewITSM/Forms/frmCatalogMng.htm", 2, false);
arrOperateMenu[18] = new Array("50203", "502", "服務單位管理", "/NewITSM/AppForms/frmBr_MastCustomerMain.aspx", 2, false);
arrOperateMenu[19] = new Array("50204", "502", "供應商管理", "/NewITSM/Provide/frmPro_ProvideManageMain.aspx", 2, false);
arrOperateMenu[20] = new Array("50205", "502", "桌面項管理", "/NewITSM/mydestop/frmEa_DefineMainPageMain.aspx", 2, false);
arrOperateMenu[21] = new Array("50206", "502", "通用表單配置", "/NewITSM/AppForms/frmappfieldconfig.aspx", 2, false);
arrOperateMenu[22] = new Array("50207", "502", "所有管理流程", "/NewITSM/Forms/form_all_flowmodel.aspx", 2, false);
arrOperateMenu[23] = new Array("50208", "502", "常用流程配置", "/NewITSM/Forms/form_flowmodel_set.aspx", 2, false);
arrOperateMenu[24] = new Array("502", "5", "基礎資料", "", 1, true);
arrOperateMenu[25] = new Array("503", "5", "客戶管理", "/NewITSM/AppForms/frmBr_ECustomerMain.aspx", 1, false);
arrOperateMenu[26] = new Array("504", "5", "資產管理", "/NewITSM/EquipmentManager/frmEqu_Main.htm", 1, false);
arrOperateMenu[27] = new Array("505", "5", "資產配置項管理", "/NewITSM/EquipmentManager/frmEqu_SchemaItemsMain.aspx", 1, false);
arrOperateMenu[28] = new Array("506", "5", "資產類別管理", "/NewITSM/EquipmentManager/frmSubject.htm", 1, false);
E8MenuConfig.Items = arrOperateMenu;</script>
創建數組的腳本爲後臺代碼根據sitemap內容和權限管理輸出的
4.設計彈出窗口的自動隱藏邏輯,保證用戶的使用便利性.
解決思路: 彈出窗口輸出的HTML中加入一段自動隱藏的代碼.
strTemp += "function HidPopup(){if(blnSubShow==false){if(parent.blnSubShow!=null) parent.blnSubShow=false;if(" + parentTreeNode + ".E8MenuConfig.WindowsList[" + deep + "]!=null)" + parentTreeNode + ".E8MenuConfig.WindowsList[" + deep + "].hide();}}";
strTemp += "</script>";
strTemp += "<body leftmargin=/"0/" topmargin=/"0/" scroll=/"no/" style=/"border:solid menu 0pxpx;/" οnmοuseοver=/"clearTimeout(parent.popt);if(parent.blnSubShow!=null) parent.blnSubShow=true;/" οnmοuseοut=/"parent.popt=setTimeout('HidPopup()',10);/" >/n";
此代碼中使用到一些技巧, 當有下一級菜單彈出時, blnSubShow = true, 則自動執行的代碼中不會隱藏窗口,一旦下級菜單隱藏後,上級菜單的 blnSubShow 爲true,自動執行的代碼會隱藏當前窗口.
5. siteMap內容如何與腳本文件結合
爲了保證與OUTLOOK風格菜單的兼容性( 登陸時可以選擇), E8.Net中做了特殊的處理方式.根據SiteMap內容,權限及是否超級管理員專門做了後臺代碼進行輸出,主要內容是一級菜單的HTML腳本和生成數組的腳本.
(非E8.Net用戶使用這個E8NetMenu.js的時候可以根據數組格式自行開發相應代碼和一級菜單的HTML腳本)
6. 其它注意事項不一一描述,此代碼經過將近3天及加班的調試和完善,全部的腳本文件E8NetMenu.js 文件內容如下,供大家參考
{
if(null==window.fe005e9f_e51b_4307_88ff_b4b150368fd4)
{
window.fe005e9f_e51b_4307_88ff_b4b150368fd4=0;
}
window.random=function()
{
var s="RID";
var d=new Date();
s+=d.getYear();
s+=d.getMonth();
s+=d.getDate();
s+=d.getHours();
s+=d.getMinutes();
s+=d.getSeconds();
s+=d.getMilliseconds();
s+=parseInt(Math.random()*1000000000000);
s+=(window.fe005e9f_e51b_4307_88ff_b4b150368fd4++);
return s;
}
}
if(null==window.absoluteLocation)
{
window.absoluteLocation=function(element, offset)
{ var c = 0; while (element) { c += element[offset]; element = element.offsetParent; } return c;
}
}
if(null==window.$)
{
window.$=function()
{
var elements = new Array();
for (var i = 0; i < arguments.length; i++)
{
var element = arguments[i];
if (typeof element == 'string')
element = document.getElementById(element);
if (arguments.length == 1)
return element;
elements.push(element);
}
return elements;
}
}
if(null==window.E8MenuConfig)
{
window.E8MenuConfig=function()
{
this.id=random();
}
window.FrameMenu=new E8MenuConfig();//create a new instance
E8MenuConfig.Items=new Array();
E8MenuConfig.WindowsList=new Array();
E8MenuConfig.TopWindow=window.createPopup();
E8MenuConfig.ShowSubMenu=function(MenuId,obj,img,deep,topLeft)
{
var strTemp = "";
var MenuUrl;
var blnHasAdd = false;
var topL = topLeft;
var LineCount = 0; //菜單行數
var MaxCharCount = 0; //每行字數
if(obj!=selectObj && deep == 1)
{
//第一層改變背景
obj.background="images/"+img;
}
var parentTreeNode="parent";
for(var i=0;i<(deep-1);i++)
{
parentTreeNode+=".parent";
}
var left = absoluteLocation(obj,'offsetLeft');
var top = absoluteLocation(obj,'offsetTop');
if(deep<=1)
{
if((obj==document||obj==document.body )&&event!=null)
{
left=event.x;
top=event.y;
}
else
{
top+= obj.offsetHeight - 4;;
}
oPopup=E8MenuConfig.WindowsList[deep];
if(null==oPopup)
{
oPopup = window.createPopup();
}
topL = left; //記錄最上層的left
}
else
{
oPopup= E8MenuConfig.WindowsList[deep];
if(null==oPopup)
{
oPopup=obj.document.parentWindow.window.createPopup();
}
}
E8MenuConfig.WindowsList[deep]=oPopup;
E8MenuConfig.hideAllWindows(deep); //關閉後面的窗口
for (var i = 0; i < E8MenuConfig.Items.length; i++)
{
if (E8MenuConfig.Items[i][1] == MenuId)
{
MenuUrl = E8MenuConfig.Items[i][3];
if(blnHasAdd == false)
{
strTemp += "<script>var blnSubShow = false;";
strTemp += "function HidPopup(){if(blnSubShow==false){if(parent.blnSubShow!=null) parent.blnSubShow=false;if(" + parentTreeNode + ".E8MenuConfig.WindowsList[" + deep + "]!=null)" + parentTreeNode + ".E8MenuConfig.WindowsList[" + deep + "].hide();}}";
strTemp += "</script>";
strTemp += "<body leftmargin=/"0/" topmargin=/"0/" scroll=/"no/" style=/"border:solid menu 0pxpx;/" οnmοuseοver=/"clearTimeout(parent.popt);if(parent.blnSubShow!=null) parent.blnSubShow=true;/" οnmοuseοut=/"parent.popt=setTimeout('HidPopup()',10);/" >/n";
strTemp += "<table width=/"100%/" height=/"100%/" style=/"border-collapse:collapse;/">/n";
}
blnHasAdd = true;
LineCount++;
if (E8MenuConfig.Items[i][2].length > MaxCharCount) MaxCharCount = E8MenuConfig.Items[i][2].length;
if (E8MenuConfig.Items[i][5]) //有下級菜單
{
strTemp += "<tr><td bgcolor=/"#C2D2E5/" style=/"border-top:#cccccc 1px solid;border-bottom:#666666 1px solid;border-left:#cccccc 1px solid;border-right:#666666 1px solid;mouse:hand; font-size:12px; color:#000000;text-align:left;vertical-align:center;CURSOR:hand/" οnmοuseοver=/"this.bgColor='#dfdfdf';" + parentTreeNode + ".E8MenuConfig.ShowSubMenu('" + E8MenuConfig.Items[i][0] + "',this,''," + (deep+1) +"," + topL + ");/" οnmοuseοut=/"this.blnSubShow=false;this.bgColor='#C2D2E5';/" height=/"20/" οnclick=/"" + parentTreeNode + ".E8MenuConfig.GoToUrl('" + MenuUrl + "');/">" + E8MenuConfig.Items[i][2] + ">></td></tr>";
MaxCharCount += 2; //多了 兩個 >符號
}
else
{
strTemp += "<tr><td bgcolor=/"#C2D2E5/" style=/"border-top:#cccccc 1px solid;border-bottom:#666666 1px solid;border-left:#cccccc 1px solid;border-right:#666666 1px solid;mouse:hand; font-size:12px; color:#000000;text-align:left;vertical-align:center;CURSOR:hand/" οnmοuseοver=/"this.bgColor='#dfdfdf';/" οnmοuseοut=/"this.blnSubShow=false;this.bgColor='#C2D2E5';/" height=/"20/" οnclick=/"" + parentTreeNode + ".E8MenuConfig.GoToUrl('" + MenuUrl + "');/">" + E8MenuConfig.Items[i][2] + "</td></tr>";
}
}
}
if(blnHasAdd == true)
{
strTemp += "</table>/n";
strTemp += "</body>/n";
}
oPopup.document.body.innerHTML="";
if (strTemp.length > 0)
oPopup.document.write(strTemp);
//顯示子菜單
if (strTemp.length > 0)
{
var LineHeight = 20; //行高
//定義打開的oPopup的寬度,高度
var width = (MaxCharCount + 1) * 12; //一般爲中文
if (width < 90) width = 90;
//如果是2層或以上,初始位置
if(deep > 1)
{
left += obj.offsetWidth - 3;
//如果到了屏幕的右邊,則從左邊開始
if(topLeft + width * 2 > screen.availWidth)
{
left = left - obj.offsetWidth - width + 3;
}
}
var height = LineCount * LineHeight;
oPopup.show(left,top, width, height, document.body);
}
}
E8MenuConfig.hideAllWindows=function(deep)
{
for(var n=deep;null!=E8MenuConfig.WindowsList && n<E8MenuConfig.WindowsList.length;n++)
{
if(null!=E8MenuConfig.WindowsList[n] && null!=E8MenuConfig.WindowsList[n].hide)
{
E8MenuConfig.WindowsList[n].hide();
}
}
}
E8MenuConfig.GoToUrl=function(url)
{
E8MenuConfig.hideAllWindows(0);
if(url != "")
window.top.MainFrame.location=url;
}
}
採用createpopup實現無限級別的彈出菜單的技術遺憾.
由於IE缺省安全設置中禁用了 "允許由腳本初始化窗口,不受大小位置的限制",如果遇到三級以上菜單時可能會出現窗口位置不受控制的情況. 需要打開此設置.
爲產品推廣應用增加了一些阻力.
在這裏感謝E8.Net合作伙伴的朋友提供的參考資料和建議.
E8.Net 工作流平臺提供了此功能全部的源代碼,用戶可以直接使用或參考,並在此基礎上更加的完善。歡迎E8.Net工作流平臺的老客戶索取相關技術及全部代碼
E8.Net工作流架構大量節約用戶的開發成本爲企業應用開發提供起點,提升軟件生產力,歡迎訪問:http://www.feifanit.com.cn/productFlow.htm