<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 < 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 < 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 < 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 >= iX1 && iX <= iX2 && iY > iY1 && iY <= 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"></script> <script type="text/javascript" src="http://www.myfootprints.cn/jsLib/eventUtil.js"></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 < 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 < 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 < 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 >= iX1 && iX <= iX2 && iY > iY1 && iY <= 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">我的博客</a></li> </ul> </li> </ul> </div><!-- End compressGUIMenu --> <script type="text/javascript">mfDDM.setup(document.getElementById('compressGUIMenu'));</script> </body> </html>