<div style="text-indent: 2em;">

本文提供了一个构建网页下拉菜单的解决方案。

此方案的结构可以很方便的重用,因为它将网页的结构、网页的行为、网页的外观分开了。

查看示例网页:网页下拉菜单示例

网页的结构使用HTML文件构建,而其外观则由CSS文件决定,其行为则由JavaScript文件控制。只要修改其CSS文件,便能让下拉菜单呈现不同的外观。而要将网页的某一个部分的行为设置成下拉菜单的行为,只需要一行JavaScript语句即可。即:

mfDDM.setup(divID);

其中参数divID是将要改变其行为的层的ID值。当然,如果你了解一些网页编程常识的话,你应该知道直接调用上述一行代码并不能起作用,你还需要引用一些核心代码文件,而这也非常简单,只需要在你的网页代码的标签之间添加三行代码,如下:

...
<head>
...
<script type="text/javascript" src="http://www.myfootprints.cn/jsLib/detect.js">
<script type="text/javascript" src="http://www.myfootprints.cn/jsLib/eventUtil.js">
<script type="text/javascript" src="http://www.myfootprints.cn/jsLib/DropDownMenu.js">
...
</head>
...

如果你满足于“拿来-使用”,你会发现看到这里就已经足够了,因为它已经能够工作得很好了。

当然,前提是你的计算机连接到了因特网。因为上面引用的核心代码文件位于我的网站服务器上。

我来解释一下那三个文件,前两个文件detect.js和eventUtil.js是用来探测浏览器和统一不同浏览器中的事件对象模型的,由非常专业的人士所编写(改天再来详细介绍),所以有了它们,可以保证我们的javascript代码在各种浏览器中都能如期运行。第三个文件DropDownMenu.js才是真正的构建下拉菜单的核心Javascript程序文件。

如果你不满足于“拿来-使用”,或者担心我的网站服务器不像那些大的网站(如Google什么的)那么稳定可靠,从而对引用我的网站服务器上的文件感到不踏实,那么你应该继续往下看,了解整个构建过程,并将代码永久地拷贝在自己的服务器上。

构建网页下拉菜单的步骤:

如果你不太熟悉JavaScript编程,那么当你往下看的时候,你可能会被那么长的代码吓坏。不过好在,我已经做好了所有的功课,它们可以很好地运行。所以如果你不想仔细深究那么长的代码的含义的话,那就不用细看了,可以拷贝下来先。

首先,建立如下的HTML结构:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>下拉菜单示例</title>
</head>
<body>
    <div id="compressGUIMenu">
        <ul class="menu0">
            <li class="menu0">文件(<span class="accessKey">F</span>)
                <ul class="menu1">
                    <li class="menu1">保存(<span class="accessKey">S</span>)</li>
                    <li class="menu1">另存为</li>
                    <li class="menu1"><hr class="separator" /></li>
                    <li class="menu1">退出(<span class="accessKey">X</span>)</li>
                </ul>
            </li>
            <li class="menu0">编辑(<span class="accessKey">C</span>)
                <ul class="menu1">
                    <li class="menu1">剪切</li>
                    <li class="menu1">复制</li>
                    <li class="menu1">粘贴</li>
                </ul>
            </li>
            <li class="menu0">关于(<span class="accessKey">A</span>)
                <ul class="menu1">
                    <li class="menu1"><a href="http://www.myfootprints.cn/blog">我的博客</a></li>
                </ul>
            </li>
        </ul>
    </div><!-- End compressGUIMenu -->
</body>
</html>

然后,建立菜单的CSS文件,如下:

#compressGUIMenu {
    background-color: #ECECEC;
    display: block;
    border: solid 1px #EcEcEc;
    height: 1.5em;
    float: none;
    clear: both;
}

#compressGUIMenu ul { list-style: none; padding: 0; margin: 0; }

#compressGUIMenu ul.menu0 li { float: left; position: relative; padding: 0 5px; height: 20px; }

#compressGUIMenu ul.menu1 { position: absolute; left: 0; top: 20px; width: 150px; border: solid 1px #0A246A; background-color: #F9F8F7; display: none; z-index: 20; }

#compressGUIMenu ul.menu1 li { float: none; clear: both; position: relative; }

第三,建立如下的JavaScript文件如下:

/**
 * Code mfDropDownMenu.js.
 * Version 1.0
 * Copyright (C) 2008- jie.tian@myfootprints.cn.
 * http://www.myfootprints.cn
 * 
 * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General 
 * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) 
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 *
 */

// // Create name spaces // var mfDDM = { Version: '1.0', DropDownMenus: {} };

// make an alias mfDropDownMenu = mfDDM;

// // DropDownMenu Object // mfDDM.DropDownMenu = function () { this.menuNode = null; this.current = false; }

mfDDM.setup = function (oMenuNode) { var dropDownMenu = null;

dropDownMenu = new mfDDM.DropDownMenus.DropDownMenu;
dropDownMenu.menuNode = oMenuNode;

// 如果不是UL结点,则寻找其子结点,直到找到UL结点为止

if (dropDownMenu.menuNode.nodeName != 'UL') {
    dropDownMenu.menuNode = dropDownMenu.findChild(dropDownMenu.menuNode, 'UL');
}

if (typeof(dropDownMenu.menuNode) == 'undefined') {
    return false;
}
var oMenus = dropDownMenu.menuNode.childNodes;

var fnShowMenu = function (v) {dropDownMenu.showMenu(v);};
var fnHideMenu = function () {dropDownMenu.hideMenu();};

for (var i = 0; i &lt; oMenus.length; i++) {
    // set up event handlers
    EventUtil.addEventHandler(oMenus[i], 'mouseover', fnShowMenu, oMenus[i]);
    EventUtil.addEventHandler(oMenus[i], 'mouseout', fnHideMenu);

    // is there a submenu?
    var ul = dropDownMenu.findChild(oMenus[i], 'UL');
    if (ul) {
        ul.style.display = 'none';
        for (var j = 0; j &lt; ul.childNodes.length; j++) {
            EventUtil.addEventHandler(ul.childNodes[j], 'mouseover', fnShowMenu, ul.childNodes[j]);
            EventUtil.addEventHandler(ul.childNodes[j], 'mouseout', fnHideMenu);
        }
    }
}

};

// // find the first child object of a particular type // mfDDM.DropDownMenu.prototype.findChild = function (obj, tag) { if (typeof(obj) != 'object') { return null; } if (obj.hasChildNodes()) { var cn = obj.childNodes; for (var k = 0; k < cn.length; k++) { if (cn[k].nodeName == tag) return cn[k]; } } else { return null; } };

// // find all the children objects of a particular type // mfDDM.DropDownMenu.prototype.findChildren = function (obj, tag) { var children = new Array(); var cn = obj.childNodes;

for (var k = 0; k &lt; cn.length; k++) {
    if (cn[k].nodeName == tag) {
        children.push(cn[k]);
    }
}

return children;

};

// // is mouse over an object? // mfDDM.DropDownMenu.prototype.isMouseOver = function (obj, iX, iY) { var iX1 = obj.offsetLeft; var iX2 = iX1 + obj.offsetWidth; var iY1 = obj.offsetTop; var iY2 = iY1 + obj.offsetHeight;

return (iX &gt;= iX1 &amp;&amp; iX &lt;= iX2 &amp;&amp; iY &gt; iY1 &amp;&amp; iY &lt;= iY2);

};

mfDDM.DropDownMenu.prototype.showMenu = function (oMenu) { if (this.current) { // hide it this.hideMenu(); } this.current = oMenu; var ul = this.findChild(oMenu, 'UL'); if (!ul) { return; } else { ul.style.display = 'block'; } };

mfDDM.DropDownMenu.prototype.hideMenu = function () { // find the sub menu, if any var ul = this.findChild(this.current, 'UL'); if (!ul) { return; } else { ul.style.display = 'none'; } };

mfDDM.DropDownMenus.DropDownMenu = function () {

};

mfDDM.DropDownMenus.DropDownMenu.prototype = new mfDDM.DropDownMenu;

最后,将以上全部整合,如下。将如下代码拷贝,粘贴到一个文本文件,将它的后缀名改为“.htm”(注意以utf-8格式保存哦,否则中文可能会显示为乱码),双击运行即可查看效果。

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
#compressGUIMenu {
    background-color: #ECECEC;
    display: block;
    border: solid 1px #EcEcEc;
    height: 1.5em;
    float: none;
    clear: both;
}

#compressGUIMenu ul { list-style: none; padding: 0; margin: 0; }

#compressGUIMenu ul.menu0 li { float: left; position: relative; padding: 0 5px; height: 20px; }

#compressGUIMenu ul.menu1 { position: absolute; left: 0; top: 20px; width: 150px; border: solid 1px #0A246A; background-color: #F9F8F7; display: none; z-index: 20; }

#compressGUIMenu ul.menu1 li { float: none; clear: both; position: relative; } </style> <script type="text/javascript" src="http://www.myfootprints.cn/jsLib/detect.js"&gt;&lt;/script> <script type="text/javascript" src="http://www.myfootprints.cn/jsLib/eventUtil.js"&gt;&lt;/script> <script type="text/javascript"> /**

  • Code mfDropDownMenu.js.
  • Version 1.0
  • Copyright (C) 2008- jie.tian@myfootprints.cn.
  • http://www.myfootprints.cn
  • This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General
  • Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option)
  • any later version.
  • This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
  • warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

*/

// // Create name spaces // var mfDDM = { Version: '1.0', DropDownMenus: {} };

// make an alias mfDropDownMenu = mfDDM;

// // DropDownMenu Object // mfDDM.DropDownMenu = function () { this.menuNode = null; this.current = false; }

mfDDM.setup = function (oMenuNode) { var dropDownMenu = null;

dropDownMenu = new mfDDM.DropDownMenus.DropDownMenu;
dropDownMenu.menuNode = oMenuNode;

// 如果不是UL结点,则寻找其子结点,直到找到UL结点为止

if (dropDownMenu.menuNode.nodeName != 'UL') {
    dropDownMenu.menuNode = dropDownMenu.findChild(dropDownMenu.menuNode, 'UL');
}

if (typeof(dropDownMenu.menuNode) == 'undefined') {
    return false;
}
var oMenus = dropDownMenu.menuNode.childNodes;

var fnShowMenu = function (v) {dropDownMenu.showMenu(v);};
var fnHideMenu = function () {dropDownMenu.hideMenu();};

for (var i = 0; i &lt; oMenus.length; i++) {
    // set up event handlers
    EventUtil.addEventHandler(oMenus[i], 'mouseover', fnShowMenu, oMenus[i]);
    EventUtil.addEventHandler(oMenus[i], 'mouseout', fnHideMenu);

    // is there a submenu?
    var ul = dropDownMenu.findChild(oMenus[i], 'UL');
    if (ul) {
        ul.style.display = 'none';
        for (var j = 0; j &lt; ul.childNodes.length; j++) {
            EventUtil.addEventHandler(ul.childNodes[j], 'mouseover', fnShowMenu, ul.childNodes[j]);
            EventUtil.addEventHandler(ul.childNodes[j], 'mouseout', fnHideMenu);
        }
    }
}

};

// // find the first child object of a particular type // mfDDM.DropDownMenu.prototype.findChild = function (obj, tag) { if (typeof(obj) != 'object') { return null; } if (obj.hasChildNodes()) { var cn = obj.childNodes; for (var k = 0; k < cn.length; k++) { if (cn[k].nodeName == tag) return cn[k]; } } else { return null; } };

// // find all the children objects of a particular type // mfDDM.DropDownMenu.prototype.findChildren = function (obj, tag) { var children = new Array(); var cn = obj.childNodes;

for (var k = 0; k &lt; cn.length; k++) {
    if (cn[k].nodeName == tag) {
        children.push(cn[k]);
    }
}

return children;

};

// // is mouse over an object? // mfDDM.DropDownMenu.prototype.isMouseOver = function (obj, iX, iY) { var iX1 = obj.offsetLeft; var iX2 = iX1 + obj.offsetWidth; var iY1 = obj.offsetTop; var iY2 = iY1 + obj.offsetHeight;

return (iX &gt;= iX1 &amp;&amp; iX &lt;= iX2 &amp;&amp; iY &gt; iY1 &amp;&amp; iY &lt;= iY2);

};

mfDDM.DropDownMenu.prototype.showMenu = function (oMenu) { if (this.current) { // hide it this.hideMenu(); } this.current = oMenu; var ul = this.findChild(oMenu, 'UL'); if (!ul) { return; } else { ul.style.display = 'block'; } };

mfDDM.DropDownMenu.prototype.hideMenu = function () { // find the sub menu, if any var ul = this.findChild(this.current, 'UL'); if (!ul) { return; } else { ul.style.display = 'none'; } };

mfDDM.DropDownMenus.DropDownMenu = function () {

};

mfDDM.DropDownMenus.DropDownMenu.prototype = new mfDDM.DropDownMenu; </script> <title>下拉菜单示例</title> </head> <body> <div id="compressGUIMenu"> <ul class="menu0"> <li class="menu0">文件(<span class="accessKey">F</span>) <ul class="menu1"> <li class="menu1">保存(<span class="accessKey">S</span>)</li> <li class="menu1">另存为</li> <li class="menu1"><hr class="separator" /></li> <li class="menu1">退出(<span class="accessKey">X</span>)</li> </ul> </li> <li class="menu0">编辑(<span class="accessKey">C</span>) <ul class="menu1"> <li class="menu1">剪切</li> <li class="menu1">复制</li> <li class="menu1">粘贴</li> </ul> </li> <li class="menu0">关于(<span class="accessKey">A</span>) <ul class="menu1"> <li class="menu1"><a href="http://www.myfootprints.cn/blog"&gt;我的博客&lt;/a&gt;&lt;/li> </ul> </li> </ul> </div><!-- End compressGUIMenu --> <script type="text/javascript">mfDDM.setup(document.getElementById('compressGUIMenu'));</script> </body> </html>