簡介
通過使用 DHTML effects , 有選擇地顯示或隱藏 HTML 頁面的一部分 , 往往可以用來創(chuàng)建在 HTML 中動態(tài)顯示的菜單。 WebLogic Portal 創(chuàng)建菜單使用的技巧是,將菜單項(xiàng)包圍在標(biāo)準(zhǔn)的 HTML DIV 元素中。這些元素是通過嵌入在頁面,以及JavaScript 支持 文件(如 menu.js )中的 JavaScript 代碼,來打開和關(guān)閉的。下面是顯示方式的簡單示例:
<DIV id=‘menu1Title‘ onClick=‘toggle("menu1")‘>File</DIV><DIV id=‘menu1‘> <DIV id=‘menuItem1‘>Open</DIV> <DIV id=‘menuItem2‘>Close</DIV> <DIV id=‘menuItem3‘>Exit</DIV></DIV>
上面是一個很標(biāo)準(zhǔn)的例子 , 一般來說 , 門戶開發(fā)人員沒有必要知道這一底層實(shí)現(xiàn)機(jī)制。但是,有些瀏覽器極不穩(wěn)定,從而導(dǎo)致上述技巧出現(xiàn)問題。在 Mozilla 和 Firefox 中運(yùn)行正常的解決方案,在 IE 中使用時卻會產(chǎn)生問題 , 原因在于處理窗口控件的 IE 工件。
窗口控件 是 Windows 開發(fā)人員使用的一個術(shù)語 , 指的是具有窗口句柄的控件 ( HWND ,為您這樣的 Win32 高手提供 ) 。這些控件由操作系統(tǒng)來管理和實(shí)施 , 而不是瀏覽器。 Microsoft 創(chuàng)建 IE 時,選擇使用了現(xiàn)有的組合框(窗口控件)的 Windows 實(shí)現(xiàn)工具作為 HTML SELECT元素的實(shí)現(xiàn)工具。此外 , 其他嵌入式對象 ( 包括 ActiveX 、 Flash 和 Adobe PDF 查看器 ) 也都是作為窗口控件來現(xiàn)實(shí)的。
本文的目的在于,您不必了解句柄和 Win32 ,但是需要認(rèn)識到,一旦操作系統(tǒng)(而非瀏覽器)管理了窗口控件,基于窗口控件的 HTML 元素,就可能具有了與規(guī)則 HTML 元素不同的字符。
出現(xiàn)的問題
簡單地說 , 在 Web 頁面中動態(tài)放置和顯示 DIV 元素時,窗口控件就成了 IE 中長期存在的問題根源。尤其是,窗口控件在通過 DIV 顯示時,將破壞預(yù)期的效果。 這一點(diǎn)在使用 DIV 元素顯示菜單的 Web 頁中尤為明顯,遺憾的是,這一問題嚴(yán)重地影響著 WebLogic Portal 中的菜單,如圖 1 所示。
在此圖中 , 第一個 portlet 中的各種框遮蓋了下拉菜單 , 結(jié)果導(dǎo)致菜單無法有效使用。如大多數(shù) HTML 開發(fā)人員所知道的那樣,在瀏覽器中,分層的 HTML 元素的顯示是由 zIndex 屬性來控制的。具有較高 zIndex 的元素顯示在具有較低 zIndex 的元素的上面。問題產(chǎn)生的原因是, IE 對 HTML 元素的 zIndex 和窗口控件的 zIndex 的處理方式不同,它總是將窗口控件置于所有 HTML 元素的上面。這可能導(dǎo)致無法將 DIV 顯示在 SELECT 上面 , 而不是讓 SELECT 穿過 DIV 顯示。
此問題在 DHTML zIndex 屬性的 MSDN documentation 中已有介紹 , 其中明確闡述了 zIndex 屬性并不支持窗口控件。
解決方案
在 IE 5.5 及其更高版本中,解決此問題極為簡單 , 因?yàn)樗鼈兙哂邢喈?dāng)新的 JavaScript 技巧,如對 IFRAME 元素行為的更改。在 IE 5.5 及其更高版本中 , IFRAME 元素的 zIndex 同時考慮到了窗口控件和 HTML 元素。這意味著,用戶可以將 IFRAME 置于 SELECT之上,它將遮蓋 SELECT 窗口控件。此外,還可以將 DIV 覆蓋在 IFRAME的上面,它所遮蓋的 IFRAME 或 SELECT 都將不再顯示。
這一特殊的 IFRAME 被 置于 DIV 的 下面以隱藏窗口控件 ,它被 稱為 墊片 , 因?yàn)樗鼉H用于遮蓋 DIV 。許多資料都討論了如何使用此技巧,在下述參考部分中,我們重點(diǎn)介紹其中之一。除此之外,在 MSDN 文檔資料中,還包括了對 IFRAME 元素的 zIndex 屬性的行為更改。
在 WebLogic Portal 中使用墊片技術(shù)
現(xiàn)在我們了解了墊片技術(shù) , 我們需要將其應(yīng)用于 WebLogic Portal 菜單。幸運(yùn)的是, WebLogic Portal 中的菜單是由 JavaScript 生成的,因此我們將墊片用于菜單極為方便。只需要修改一個文件(menu.js)即可,該文件位于 framework/skins/default/js 目錄中。證明 menu.js 是如何顯示菜單的,超出了本文討論的范圍,但是關(guān)于此過程的詳細(xì)信息可以在 WebLogic Portal User Interface Framework Guide 中找到。
首先我們需要進(jìn)行的修改是,添加所有新的墊片功能 , 以便根據(jù)需要創(chuàng)建、顯示和隱藏這些墊片。注意,因?yàn)楫?dāng)用戶通過各子菜單下溯時 WebLogic Portal 會 同時顯示出很多菜單,所以我們需要具有創(chuàng)建和顯示多個墊片的能力。從本質(zhì)上說,在墊片和每個菜單之間存在著一一對應(yīng)的關(guān)系。創(chuàng)建每個墊片時 , 它都具有一個同與之關(guān)聯(lián)的菜單相對應(yīng)的標(biāo)識。
不幸的是 , 因?yàn)樵?WebLogic 服務(wù)包之間 , menu.js 可能發(fā)生變更 ,所以 提供經(jīng)過修改的 menu.js 是不可行的。反之,要應(yīng)用此解決方案,用戶需要手動修改 menu.js 文件,但是請放心,這是一個很簡單的任務(wù)。
第一個步驟是將那些基本的 JavaScript 功能,添加到以后打開和關(guān)閉菜單時將要引用的文件中。這些功能如下所示,將這些功能附加在 menu.js 的結(jié)尾處即可。
//Opens a shim, if no shim exists for the menu, one is createdfunction openShim(menu,menuItem){ if (menu==null) return; var shim = getShim(menu); if (shim==null) shim = createMenuShim(menu,getShimId(menu)); //Change menu zIndex so shim can work with it menu.style.zIndex = 100; var width = (menu.offsetWidth == 0 ? menuItem.renderedWidth : menu.offsetWidth); var height; if (menu.offsetHeight == 0) { var menus = getMenuItemCount(menu); height = menuItem.renderedHeight * menus; } else { var height = menu.offsetHeight; } shim.style.width = width; shim.style.height = height; shim.style.top = menu.style.top; shim.style.left = menu.style.left; shim.style.zIndex = menu.style.zIndex - 1; shim.style.position = "absolute"; shim.style.display = "block";}//Closes the shim associated with the menufunction closeShim(menu){ if (menu==null) return; var shim = getShim(menu); if (shim!=null) shim.style.display = "none";}//Creates a new shim for the menufunction createMenuShim(menu){ if (menu==null) return null; var shim = document.createElement("<iframe scrolling=‘no‘ frameborder=‘0‘"+ "style=‘position:absolute; top:0px;"+ "left:0px; display:none‘></iframe>"); shim.name = getShimId(menu); shim.id = getShimId(menu); //Unremark this line if you need your menus to be transparent for some reason //shim.style.filter="progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)"; if (menu.offsetParent==null || menu.offsetParent.id=="") { window.document.body.appendChild(shim); } else { menu.offsetParent.appendChild(shim); } return shim;}//Creates an id for the shim based on the menu idfunction getShimId(menu){ if (menu.id==null) return "__shim"; return "__shim"+menu.id;}//Returns the shim for a specific menufunction getShim(menu){ return document.getElementById(getShimId(menu));}function getMenuItemCount(menu){ var count = 0; var child = menu.firstChild; while (child) { if (child.nodeName=="DIV") count = count + 1; child = child.nextSibling; } return count; }
將這些新功能粘貼到 menu.js 的底部后 , 下一個步驟是將這些新功能應(yīng)用于各種菜單功能中。第一個要更改的功能稱為openMenu()。如果在menu.js中搜索它,則可以看到它帶有三個參數(shù):menuItem、menu和depth。在此,您需要做的只是在該方法的結(jié)尾處添加一個新的代碼行:
openShim(menu,menuItem);
注意 , 此為對我們先前添加的一種功能的調(diào)用。它的作用是,確保每次打開菜單時創(chuàng)建和顯示墊片。
下一個修改是 , 確保在關(guān)閉菜單時關(guān)閉墊片。為此,需要修改menu.js中的closeAllChildren()方法。尤其是,需要在該方法中添加一個行;首先在該方法中查找此現(xiàn)有行:
subMenu.style.display = "none";
在此行的后面 , 添加一個關(guān)閉墊片的新行 :
closeShim(subMenu);
注意 , 這一行也是對我們先前粘貼的一種功能的調(diào)用。
恭喜 ! 您已經(jīng)完成的修改。如果沒有什么差錯 , 則在 IE 5.5 和更高版本中 , 您的 WebLogic Portal 菜單現(xiàn)在應(yīng)該正常運(yùn)行了 , 如圖 2 所示。
結(jié)束語
本文闡明了通過 Internet Explorer 呈現(xiàn)頁面時 HTML 元素有時被其他 DHTML 元素隱藏的問題。我們介紹了使用IFRAME墊片方便地解決此問題的方式,并演示了如何修改 WebLogic Portal 以利用此解決方案的方法。結(jié)果形成了提高門戶外觀并增強(qiáng)用戶滿意程度的解決方案。
參考資料
關(guān)于作者
Gerald Nunn 是 BEA 系統(tǒng)專業(yè)服務(wù)的業(yè)務(wù)主任顧問。