JavaScript伸缩菜单实现原理与代码解析

Noah
Noah
发布时间:2026-10-14 | 5人浏览过
原创

实现一个简单的伸缩菜单主要依赖于DOM操作来切换CSS类名。本示例展示了如何通过原生JavaScript监听点击事件,并动态改变子列表的显示状态,从而构建出具有层级交互功能的导航栏。

核心实现思路

伸缩菜单的核心逻辑在于控制子元素的可见性。在HTML结构中,主菜单项作为父级元素包裹着对应的子菜单。默认情况下,子菜单被隐藏;当用户点击主菜单项时,脚本检测当前子菜单的状态,并将其切换为显示或隐藏。这种切换通过修改元素的CSS class 属性来实现,利用CSS中的 display: none 和 display: block 规则控制渲染。

代码结构分析

完整的示例包含HTML结构、CSS样式和JavaScript逻辑三个部分。以下是整理后的标准代码实现:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>伸缩的菜单</title>
    <style>
        /* 页面基础样式 */
        body {
            background-color: #ffdee0;
        }

        /* 导航容器 */
        #navigation {
            width: 200px;
            font-family: Arial, sans-serif;
        }

        /* 一级菜单列表重置 */
        #navigation > ul {
            list-style-type: none;
            margin: 0;
            padding: 0;
        }

        /* 一级菜单项下边框 */
        #navigation > ul > li {
            border-bottom: 1px solid #ED9F9F;
        }

        /* 一级菜单链接样式 */
        #navigation > ul > li > a {
            display: block;
            padding: 5px 5px 5px 0.5em;
            text-decoration: none;
            border-left: 12px solid #711515;
            border-right: 1px solid #711515;
        }

        /* 一级菜单链接:默认与访问过 */
        #navigation > ul > li > a:link,
        #navigation > ul > li > a:visited {
            background-color: #c11136;
            color: #FFFFFF;
        }

        /* 一级菜单链接:悬停效果 */
        #navigation > ul > li > a:hover {
            background-color: #990020;
            color: #ffff00;
        }

        /* 二级菜单容器重置 */
        #navigation ul li ul {
            list-style-type: none;
            margin: 0;
            padding: 0;
        }

        /* 二级菜单项上边框 */
        #navigation ul li ul li {
            border-top: 1px solid #ED9F9F;
        }

        /* 二级菜单链接样式 */
        #navigation ul li ul li a {
            display: block;
            padding: 3px 3px 3px 0.5em;
            text-decoration: none;
            border-left: 28px solid #a71f1f;
            border-right: 1px solid #711515;
        }

        /* 二级菜单链接:默认与访问过 */
        #navigation ul li ul li a:link,
        #navigation ul li ul li a:visited {
            background-color: #e85070;
            color: #FFFFFF;
        }

        /* 二级菜单链接:悬停效果 */
        #navigation ul li ul li a:hover {
            background-color: #c2425d;
            color: #ffff00;
        }

        /* 隐藏状态:通过class控制 */
        .myHide {
            display: none;
        }

        /* 显示状态:通过class控制 */
        .myShow {
            display: block;
        }
    </style>
</head>
<body>
    <div id="navigation">
        <ul id="listUL">
            <li><a href="#">Home</a></li>
            <li>
                <a href="#">News</a>
                <ul class="myHide">
                    <li><a href="#">Latest News</a></li>
                    <li><a href="#">All News</a></li>
                </ul>
            </li>
            <li>
                <a href="#">Sports</a>
                <ul class="myHide">
                    <li><a href="#">Basketball</a></li>
                    <li><a href="#">Football</a></li>
                    <li><a href="#">Volleyball</a></li>
                </ul>
            </li>
            <li>
                <a href="#">Weather</a>
                <ul class="myHide">
                    <li><a href="#">Today's Weather</a></li>
                    <li><a href="#">Forecast</a></li>
                </ul>
            </li>
            <li><a href="#">Contact Me</a></li>
        </ul>
    </div>
<script>
    // 定义切换显示的函数
    function change() {
        // 获取当前点击的li元素下的第一个ul子元素
        var oSecondDiv = this.parentNode.getElementsByTagName("ul")[0];
        
        // 根据当前class名决定切换到哪个状态
        if (oSecondDiv.className == "myHide") {
            oSecondDiv.className = "myShow";
        } else {
            oSecondDiv.className = "myHide";
        }
    }

    // 页面加载完成后初始化
    window.onload = function () {
        var oUl = document.getElementById("listUL");
        var aLi = oUl.childNodes;
        var oA;
        
        // 遍历所有子节点
        for (var i = 0; i < aLi.length; i++) {
            // 检查节点是否为li标签且包含ul子菜单
            if (aLi[i].tagName === "LI" && aLi[i].getElementsByTagName("ul").length) {
                oA = aLi[i].firstChild;
                if (oA && oA.tagName === "A") {
                    // 绑定点击事件
                    oA.onclick = change;
                }
            }
        }
    };
</script>
</body>
</html>

关键步骤解析

第1步:定义CSS状态类

在样式表中定义两个辅助类:.myHide 设置为 display: none 以隐藏元素,.myShow 设置为 display: block 以显示元素。初始状态下,所有二级菜单都应用 myHide 类,确保页面加载时子菜单是收起的。

第2步:构建HTML层级结构

使用无序列表 <ul> 嵌套 <li> 来组织菜单。<ul id="listUL"> 是一级菜单容器,每个包含子菜单的一级 <li> 内部必须包裹一个二级 <ul>。确保结构正确是后续通过DOM关系查找元素的前提。

第3步:编写切换逻辑函数

定义 change 函数。在函数内部,使用 this.parentNode.getElementsByTagName("ul")[0] 精确定位到与当前点击项相关联的子菜单。通过判断该子菜单当前的 className 是 myHide 还是 myShow,动态替换为另一个类名,从而实现视觉上的展开与收缩切换。

第4步:动态绑定事件监听

在 window.onload 中遍历一级菜单项。筛选出那些确实拥有子菜单(即包含 <ul>)的 <li> 元素,找到其内部的超链接 <a> 标签。将 change 函数赋值给链接的 onclick 属性。注意,直接赋值函数名即可,不需要调用它(即不要写成 change()),这样当事件触发时才会执行该逻辑。

常见问题与排错

  • 子菜单未隐藏或显示异常: 检查CSS中是否正确定义了 .myHide 和 .myShow 的 display 属性,并确保HTML中子菜单的初始class是 myHide。
  • 点击无效: 确认JavaScript是否在DOM元素完全加载后运行(即包裹在 window.onload 或放置在 底部)。如果脚本在元素前执行,可能无法获取到正确的DOM节点。
  • 中文乱码: 确保HTML文件头部包含 <meta charset="UTF-8">,或者在服务器端配置正确的字符集。

总结

本示例展示了如何利用原生JavaScript操作DOM属性和CSS类名来实现基础的交互效果。虽然现代框架如Vue或React提供了更简洁的组件化方案,但理解这种基于Class切换的手动DOM操作方式对于掌握前端底层原理至关重要。以上就是JavaScript实现伸缩菜单的详细内容,更多关于JavaScript交互特效的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表