本文提供了一个构建网页下拉菜单的解决方案。
此方案的结构可以很方便的重用,因为它将网页的结构、网页的行为、网页的外观分开了。
查看示例网页:网页下拉菜单示例
网页的结构使用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>