簡(jiǎn)介
通過(guò)使用 DHTML effects , 有選擇地顯示或隱藏 HTML 頁(yè)面的一部分 , 往往可以用來(lái)創(chuàng )建在 HTML 中動(dòng)態(tài)顯示的菜單。 WebLogic Portal 創(chuàng )建菜單使用的技巧是,將菜單項包圍在標準的 HTML DIV 元素中。這些元素是通過(guò)嵌入在頁(yè)面,以及JavaScript 支持 文件(如 menu.js )中的 JavaScript 代碼,來(lái)打開(kāi)和關(guān)閉的。下面是顯示方式的簡(jiǎ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>上面是一個(gè)很標準的例子 , 一般來(lái)說(shuō) , 門(mén)戶(hù)開(kāi)發(fā)人員沒(méi)有必要知道這一底層實(shí)現機制。但是,有些瀏覽器極不穩定,從而導致上述技巧出現問(wèn)題。在 Mozilla 和 Firefox 中運行正常的解決方案,在 IE 中使用時(shí)卻會(huì )產(chǎn)生問(wèn)題 , 原因在于處理窗口控件的 IE 工件。
窗口控件 是 Windows 開(kāi)發(fā)人員使用的一個(gè)術(shù)語(yǔ) , 指的是具有窗口句柄的控件 ( HWND ,為您這樣的 Win32 高手提供 ) 。這些控件由操作系統來(lái)管理和實(shí)施 , 而不是瀏覽器。 Microsoft 創(chuàng )建 IE 時(shí),選擇使用了現有的組合框(窗口控件)的 Windows 實(shí)現工具作為 HTML SELECT元素的實(shí)現工具。此外 , 其他嵌入式對象 ( 包括 ActiveX 、 Flash 和 Adobe PDF 查看器 ) 也都是作為窗口控件來(lái)現實(shí)的。
本文的目的在于,您不必了解句柄和 Win32 ,但是需要認識到,一旦操作系統(而非瀏覽器)管理了窗口控件,基于窗口控件的 HTML 元素,就可能具有了與規則 HTML 元素不同的字符。
出現的問(wèn)題
簡(jiǎn)單地說(shuō) , 在 Web 頁(yè)面中動(dòng)態(tài)放置和顯示 DIV 元素時(shí),窗口控件就成了 IE 中長(cháng)期存在的問(wèn)題根源。尤其是,窗口控件在通過(guò) DIV 顯示時(shí),將破壞預期的效果。 這一點(diǎn)在使用 DIV 元素顯示菜單的 Web 頁(yè)中尤為明顯,遺憾的是,這一問(wèn)題嚴重地影響著(zhù) WebLogic Portal 中的菜單,如圖 1 所示。

在此圖中 , 第一個(gè) portlet 中的各種框遮蓋了下拉菜單 , 結果導致菜單無(wú)法有效使用。如大多數 HTML 開(kāi)發(fā)人員所知道的那樣,在瀏覽器中,分層的 HTML 元素的顯示是由 zIndex 屬性來(lái)控制的。具有較高 zIndex 的元素顯示在具有較低 zIndex 的元素的上面。問(wèn)題產(chǎn)生的原因是, IE 對 HTML 元素的 zIndex 和窗口控件的 zIndex 的處理方式不同,它總是將窗口控件置于所有 HTML 元素的上面。這可能導致無(wú)法將 DIV 顯示在 SELECT 上面 , 而不是讓 SELECT 穿過(guò) DIV 顯示。
此問(wèn)題在 DHTML zIndex 屬性的 MSDN documentation 中已有介紹 , 其中明確闡述了 zIndex 屬性并不支持窗口控件。
解決方案
在 IE 5.5 及其更高版本中,解決此問(wèn)題極為簡(jiǎn)單 , 因為它們具有相當新的 JavaScript 技巧,如對 IFRAME 元素行為的更改。在 IE 5.5 及其更高版本中 , IFRAME 元素的 zIndex 同時(shí)考慮到了窗口控件和 HTML 元素。這意味著(zhù),用戶(hù)可以將 IFRAME 置于 SELECT之上,它將遮蓋 SELECT 窗口控件。此外,還可以將 DIV 覆蓋在 IFRAME的上面,它所遮蓋的 IFRAME 或 SELECT 都將不再顯示。
這一特殊的 IFRAME 被 置于 DIV 的 下面以隱藏窗口控件 ,它被 稱(chēng)為 墊片 , 因為它僅用于遮蓋 DIV 。許多資料都討論了如何使用此技巧,在下述參考部分中,我們重點(diǎn)介紹其中之一。除此之外,在 MSDN 文檔資料中,還包括了對 IFRAME 元素的 zIndex 屬性的行為更改。
在 WebLogic Portal 中使用墊片技術(shù)
現在我們了解了墊片技術(shù) , 我們需要將其應用于 WebLogic Portal 菜單。幸運的是, WebLogic Portal 中的菜單是由 JavaScript 生成的,因此我們將墊片用于菜單極為方便。只需要修改一個(gè)文件(menu.js)即可,該文件位于 framework/skins/default/js 目錄中。證明 menu.js 是如何顯示菜單的,超出了本文討論的范圍,但是關(guān)于此過(guò)程的詳細信息可以在 WebLogic Portal User Interface Framework Guide 中找到。
首先我們需要進(jìn)行的修改是,添加所有新的墊片功能 , 以便根據需要創(chuàng )建、顯示和隱藏這些墊片。注意,因為當用戶(hù)通過(guò)各子菜單下溯時(shí) WebLogic Portal 會(huì ) 同時(shí)顯示出很多菜單,所以我們需要具有創(chuàng )建和顯示多個(gè)墊片的能力。從本質(zhì)上說(shuō),在墊片和每個(gè)菜單之間存在著(zhù)一一對應的關(guān)系。創(chuàng )建每個(gè)墊片時(shí) , 它都具有一個(gè)同與之關(guān)聯(lián)的菜單相對應的標識。
不幸的是 , 因為在 WebLogic 服務(wù)包之間 , menu.js 可能發(fā)生變更 ,所以 提供經(jīng)過(guò)修改的 menu.js 是不可行的。反之,要應用此解決方案,用戶(hù)需要手動(dòng)修改 menu.js 文件,但是請放心,這是一個(gè)很簡(jiǎn)單的任務(wù)。
第一個(gè)步驟是將那些基本的 JavaScript 功能,添加到以后打開(kāi)和關(guān)閉菜單時(shí)將要引用的文件中。這些功能如下所示,將這些功能附加在 menu.js 的結尾處即可。
//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 的底部后 , 下一個(gè)步驟是將這些新功能應用于各種菜單功能中。第一個(gè)要更改的功能稱(chēng)為openMenu()。如果在menu.js中搜索它,則可以看到它帶有三個(gè)參數:menuItem、menu和depth。在此,您需要做的只是在該方法的結尾處添加一個(gè)新的代碼行:
openShim(menu,menuItem);
注意 , 此為對我們先前添加的一種功能的調用。它的作用是,確保每次打開(kāi)菜單時(shí)創(chuàng )建和顯示墊片。
下一個(gè)修改是 , 確保在關(guān)閉菜單時(shí)關(guān)閉墊片。為此,需要修改menu.js中的closeAllChildren()方法。尤其是,需要在該方法中添加一個(gè)行;首先在該方法中查找此現有行:
subMenu.style.display = "none";
在此行的后面 , 添加一個(gè)關(guān)閉墊片的新行 :
closeShim(subMenu);
注意 , 這一行也是對我們先前粘貼的一種功能的調用。
恭喜 ! 您已經(jīng)完成的修改。如果沒(méi)有什么差錯 , 則在 IE 5.5 和更高版本中 , 您的 WebLogic Portal 菜單現在應該正常運行了 , 如圖 2 所示。

結束語(yǔ)
本文闡明了通過(guò) Internet Explorer 呈現頁(yè)面時(shí) HTML 元素有時(shí)被其他 DHTML 元素隱藏的問(wèn)題。我們介紹了使用IFRAME墊片方便地解決此問(wèn)題的方式,并演示了如何修改 WebLogic Portal 以利用此解決方案的方法。結果形成了提高門(mén)戶(hù)外觀(guān)并增強用戶(hù)滿(mǎn)意程度的解決方案。
參考資料
關(guān)于作者
Gerald Nunn 是 BEA 系統專(zhuān)業(yè)服務(wù)的業(yè)務(wù)主任顧問(wèn)。
聯(lián)系客服