在 Internet Explorer ( IE ) 中 , 以重叠方式动态放置 HTML 元素 , 可能导致一些元素隐藏另外一些元素。不幸的是 , BEA WebLogic Portal 8.1 中 , 在包含特定 HTML 实体 ( 如 SELECT 元素或 ActiveX 控件 ) 的门户页面上使用多层菜单时 , 此事就有可能发生。讨厌的结果是,菜单可能会被部分隐藏。本文介绍了解决这一问题的 HTML 技巧,即确保在门户页面上,把菜单显示在所有其他元素之上的技巧。
简介 通过使用 DHTML effects , 有选择地显示或隐藏 HTML 页面的一部分 , 往往可以用来创建在 HTML 中动态显示的菜单。 WebLogic Portal 创建菜单使用的技巧是,将菜单项包围在标准的 HTML DIV 元素中。这些元素是通过嵌入在页面,以及JavaScript 支持 文件(如 menu.js )中的 JavaScript 代码,来打开和关闭的。下面是显示方式的简单示例: <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> 上面是一个很标准的例子 , 一般来说 , 门户开发人员没有必要知道这一底层实现机制。但是,有些浏览器极不稳定,从而导致上述技巧出现问题。在 Mozilla 和 Firefox 中运行正常的解决方案,在 IE 中使用时却会产生问题 , 原因在于处理窗口控件的 IE 工件。 窗口控件 是 Windows 开发人员使用的一个术语 , 指的是具有窗口句柄的控件 ( HWND ,为您这样的 Win32 高手提供 ) 。这些控件由操作系统来管理和实施 , 而不是浏览器。 Microsoft 创建 IE 时,选择使用了现有的组合框(窗口控件)的 Windows 实现工具作为 HTML SELECT元素的实现工具。此外 , 其他嵌入式对象 ( 包括 ActiveX 、 Flash 和 Adobe PDF 查看器 ) 也都是作为窗口控件来现实的。 本文的目的在于,您不必了解句柄和 Win32 ,但是需要认识到,一旦操作系统(而非浏览器)管理了窗口控件,基于窗口控件的 HTML 元素,就可能具有了与规则 HTML 元素不同的字符。 出现的问题 简单地说 , 在 Web 页面中动态放置和显示 DIV 元素时,窗口控件就成了 IE 中长期存在的问题根源。尤其是,窗口控件在通过 DIV 显示时,将破坏预期的效果。 这一点在使用 DIV 元素显示菜单的 Web 页中尤为明显,遗憾的是,这一问题严重地影响着 WebLogic Portal 中的菜单,如图 1 所示。
在此图中 , 第一个 portlet 中的各种框遮盖了下拉菜单 , 结果导致菜单无法有效使用。如大多数 HTML 开发人员所知道的那样,在浏览器中,分层的 HTML 元素的显示是由 zIndex 属性来控制的。具有较高 zIndex 的元素显示在具有较低 zIndex 的元素的上面。问题产生的原因是, IE 对 HTML 元素的 zIndex 和窗口控件的 zIndex 的处理方式不同,它总是将窗口控件置于所有 HTML 元素的上面。这可能导致无法将 DIV 显示在 SELECT 上面 , 而不是让 SELECT 穿过 DIV 显示。 此问题在 DHTML zIndex 属性的 MSDN documentation 中已有介绍 , 其中明确阐述了 zIndex 属性并不支持窗口控件。 解决方案 在 IE 5.5 及其更高版本中,解决此问题极为简单 , 因为它们具有相当新的 JavaScript 技巧,如对 IFRAME 元素行为的更改。在 IE 5.5 及其更高版本中 , IFRAME 元素的 zIndex 同时考虑到了窗口控件和 HTML 元素。这意味着,用户可以将 IFRAME 置于 SELECT之上,它将遮盖 SELECT 窗口控件。此外,还可以将 DIV 覆盖在 IFRAME的上面,它所遮盖的 IFRAME 或 SELECT 都将不再显示。 这一特殊的 IFRAME 被 置于 DIV 的 下面以隐藏窗口控件 ,它被 称为 垫片 , 因为它仅用于遮盖 DIV 。许多资料都讨论了如何使用此技巧,在下述参考部分中,我们重点介绍其中之一。除此之外,在 MSDN 文档资料中,还包括了对 IFRAME 元素的 zIndex 属性的行为更改。 在 WebLogic Portal 中使用垫片技术 现在我们了解了垫片技术 , 我们需要将其应用于 WebLogic Portal 菜单。幸运的是, WebLogic Portal 中的菜单是由 JavaScript 生成的,因此我们将垫片用于菜单极为方便。只需要修改一个文件(menu.js)即可,该文件位于 framework/skins/default/js 目录中。证明 menu.js 是如何显示菜单的,超出了本文讨论的范围,但是关于此过程的详细信息可以在 WebLogic Portal User Interface Framework Guide 中找到。 首先我们需要进行的修改是,添加所有新的垫片功能 , 以便根据需要创建、显示和隐藏这些垫片。注意,因为当用户通过各子菜单下溯时 WebLogic Portal 会 同时显示出很多菜单,所以我们需要具有创建和显示多个垫片的能力。从本质上说,在垫片和每个菜单之间存在着一一对应的关系。创建每个垫片时 , 它都具有一个同与之关联的菜单相对应的标识。 不幸的是 , 因为在 WebLogic 服务包之间 , menu.js 可能发生变更 ,所以 提供经过修改的 menu.js 是不可行的。反之,要应用此解决方案,用户需要手动修改 menu.js 文件,但是请放心,这是一个很简单的任务。 第一个步骤是将那些基本的 JavaScript 功能,添加到以后打开和关闭菜单时将要引用的文件中。这些功能如下所示,将这些功能附加在 menu.js 的结尾处即可。 //Opens a shim, if no shim exists for the menu, one is created function 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 menu function closeShim(menu) { if (menu==null) return; var shim = getShim(menu); if (shim!=null) shim.style.display = "none"; } //Creates a new shim for the menu function 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 id function getShimId(menu) { if (menu.id==null) return "__shim"; return "__shim"+menu.id; } //Returns the shim for a specific menu function 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 的底部后 , 下一个步骤是将这些新功能应用于各种菜单功能中。第一个要更改的功能称为openMenu()。如果在menu.js中搜索它,则可以看到它带有三个参数:menuItem、menu和depth。在此,您需要做的只是在该方法的结尾处添加一个新的代码行: openShim(menu,menuItem); 注意 , 此为对我们先前添加的一种功能的调用。它的作用是,确保每次打开菜单时创建和显示垫片。 下一个修改是 , 确保在关闭菜单时关闭垫片。为此,需要修改menu.js中的closeAllChildren()方法。尤其是,需要在该方法中添加一个行;首先在该方法中查找此现有行: subMenu.style.display = "none"; 在此行的后面 , 添加一个关闭垫片的新行 : closeShim(subMenu); 注意 , 这一行也是对我们先前粘贴的一种功能的调用。 恭喜 ! 您已经完成的修改。如果没有什么差错 , 则在 IE 5.5 和更高版本中 , 您的 WebLogic Portal 菜单现在应该正常运行了 , 如图 2 所示。
结束语 本文阐明了通过 Internet Explorer 呈现页面时 HTML 元素有时被其他 DHTML 元素隐藏的问题。我们介绍了使用IFRAME垫片方便地解决此问题的方式,并演示了如何修改 WebLogic Portal 以利用此解决方案的方法。结果形成了提高门户外观并增强用户满意程度的解决方案。 参考资料
关于作者 Gerald Nunn 是 BEA 系统专业服务的业务主任顾问。 |
|
来自: smoking_boy > 《我的图书馆》