怎样构建网页下拉菜单

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

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

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

网页的结构使用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>

Add comment

Loading