JS实现侧边导航单次仅展开一个子菜单效果
侧边导航子菜单互斥展开效果实现
现有功能说明
- 已完成侧边导航组件开发,包含2个主菜单,每个主菜单下配置了子菜单触发按钮,点击按钮可控制对应子菜单的展开、收起
- 当前交互存在的问题:子菜单展开状态互不影响,支持多个子菜单同时展开,不符合手风琴式导航的交互要求
预期实现目标
同一时间最多展示一个展开的子菜单:当已有子菜单处于展开状态时,点击其他子菜单的触发按钮,原展开的子菜单自动收起,同时展开当前点击的子菜单;点击已展开的子菜单触发按钮,则直接收起该子菜单。
现有完整代码
JavaScript 逻辑
const sub_menu = document.querySelectorAll('.sub_menu'); sub_menu.forEach((item) => { const subMenuHeader = item.querySelector('.sub_menu_header') const subMenuBody = item.querySelector('.sub_menu_body') subMenuHeader.addEventListener('click', () => { if (!subMenuBody.classList.contains('active')) { subMenuBody.classList.add('active'); } else { subMenuBody.classList.remove('active'); } }) })
CSS 样式
*{ margin: 0; padding: 0; box-sizing: border-box; text-decoration: none; list-style: none; } body{ font-family: 'Ebrima'; background-color: #444444; } nav#nav_menu_query_off{ position: fixed; top: 0; left: 0; width: 200px; height: 100vh; background-color: #222222; overflow: auto; z-index: 2; padding: 20px 0 20px 20px; } nav#nav_menu_query_off menu#main_menu li.main_list_item div.menu_header{ text-transform: uppercase; padding-bottom: 10px; } nav#nav_menu_query_off menu li{ color: #f0f0f0; } nav#nav_menu_query_off menu#main_menu li.main_list_item:not(:last-child){ padding-bottom: 20px; } nav#nav_menu_query_off menu#main_menu li.main_list_item:not(:first-child){ padding-top: 20px; } nav#nav_menu_query_off menu#main_menu div.menu_body{ padding: 0px 0 0 20px; border-left: 1px solid #efefef; } nav#nav_menu_query_off menu#main_menu div.menu_body menu.sub_menu{ padding: 10px 0px; border-bottom: 1px solid #efefef; } nav#nav_menu_query_off menu#main_menu div.menu_body menu.sub_menu div.sub_menu_header{ text-transform: capitalize; font-size: 14px; } nav#nav_menu_query_off menu#main_menu div.menu_body menu.sub_menu div.sub_menu_header:hover{ cursor: pointer; } nav#nav_menu_query_off menu#main_menu div.menu_body menu.sub_menu div.sub_menu_body{ padding: 5px 0 0 0px; display: none; } nav#nav_menu_query_off menu#main_menu div.menu_body menu.sub_menu div.sub_menu_body.active{ display: block; } nav#nav_menu_query_off menu#main_menu li.main_list_item div.menu_body menu.sub_menu div.sub_menu_body li.inner_list_item{ font-size: 14px; } nav#nav_menu_query_off menu li .menu_body menu li a{ color: #f0f0f0; display: block; padding: 5px 0 5px 20px; } nav#nav_menu_query_off menu li .menu_body menu li a:hover{ background-color: #999999; } nav::-webkit-scrollbar{ display: none; }
HTML 结构
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <link rel="stylesheet" href="./style.css" /> <title>side nav</title> </head> <body> <nav id="nav_menu_query_off"> <menu id="main_menu"> <li class="main_list_item"> <div class="menu_header">menu one</div> <div class="menu_body"> <menu class="sub_menu"> <div class="sub_menu_header">sub menu one</div> <div class="sub_menu_body"> <li class="inner_list_item"><a href="">link one</a></li> <li class="inner_list_item"><a href="">link two</a></li> <li class="inner_list_item"><a href="">link three</a></li> <li class="inner_list_item"><a href="">link four</a></li> <li class="inner_list_item"><a href="">link five</a></li> <li class="inner_list_item"><a href="">link six</a></li> <li class="inner_list_item"><a href="">link seven</a></li> </div> </menu> <menu class="sub_menu"> <div class="sub_menu_header">sub menu two</div> <div class="sub_menu_body"> <li class="inner_list_item"><a href="">link one</a></li> <li class="inner_list_item"><a href="">link two</a></li> <li class="inner_list_item"><a href="">link three</a></li> <li class="inner_list_item"><a href="">link four</a></li> <li class="inner_list_item"><a href="">link five</a></li> <li class="inner_list_item"><a href="">link six</a></li> <li class="inner_list_item"><a href="">link seven</a></li> </div> </menu> <menu class="sub_menu"> <div class="sub_menu_header">sub menu three</div> <div class="sub_menu_body"> <li class="inner_list_item"><a href="">link one</a></li> <li class="inner_list_item"><a href="">link two</a></li> <li class="inner_list_item"><a href="">link three</a></li> <li class="inner_list_item"><a href="">link four</a></li> <li class="inner_list_item"><a href="">link five</a></li> <li class="inner_list_item"><a href="">link six</a></li> <li class="inner_list_item"><a href="">link seven</a></li> </div> </menu> </div> </li> <li class="main_list_item"> <div class="menu_header">menu two</div> <div class="menu_body"> <menu class="sub_menu"> <div class="sub_menu_header">sub menu one</div> <div class="sub_menu_body"> <li class="inner_list_item"><a href="">link one</a></li> <li class="inner_list_item"><a href="">link two</a></li> <li class="inner_list_item"><a href="">link three</a></li> <li class="inner_list_item"><a href="">link four</a></li> <li class="inner_list_item"><a href="">link five</a></li> <li class="inner_list_item"><a href="">link six</a></li> <li class="inner_list_item"><a href="">link seven</a></li> </div> </menu> <menu class="sub_menu"> <div class="sub_menu_header">sub menu two</div> <div class="sub_menu_body"> <li class="inner_list_item"><a href="">link one</a></li> <li class="inner_list_item"><a href="">link two</a></li> <li class="inner_list_item"><a href="">link three</a></li> <li class="inner_list_item"><a href="">link four</a></li> <li class="inner_list_item"><a href="">link five</a></li> <li class="inner_list_item"><a href="">link six</a></li> <li class="inner_list_item"><a href="">link seven</a></li> </div> </menu> <menu class="sub_menu"> <div class="sub_menu_header">sub menu three</div> <div class="sub_menu_body"> <li class="inner_list_item"><a href="">link one</a></li> <li class="inner_list_item"><a href="">link two</a></li> <li class="inner_list_item"><a href="">link three</a></li> <li class="inner_list_item"><a href="">link four</a></li> <li class="inner_list_item"><a href="">link five</a></li> <li class="inner_list_item"><a href="">link six</a></li> <li class="inner_list_item"><a href="">link seven</a></li> </div> </menu> </div> </li> </menu> </nav> </body> </html> <script src="./script.js"></script>
修改方案
CSS和HTML代码无需调整,仅修改JavaScript逻辑即可实现互斥展开效果:
- 提前获取所有子菜单的主体元素集合
- 每次点击子菜单头部时,先记录当前点击的子菜单是否处于展开状态
- 遍历所有子菜单主体,移除全部
active类,收起所有已展开的子菜单 - 如果当前点击的子菜单之前是收起状态,就为它添加
active类完成展开;如果之前已经是展开状态,不做额外处理,实现点击收起的效果
修改后的完整JavaScript代码:
const sub_menu = document.querySelectorAll('.sub_menu'); const allSubMenuBodies = document.querySelectorAll('.sub_menu_body'); sub_menu.forEach((item) => { const subMenuHeader = item.querySelector('.sub_menu_header') const subMenuBody = item.querySelector('.sub_menu_body') subMenuHeader.addEventListener('click', () => { const isCurrentActive = subMenuBody.classList.contains('active'); // 收起所有已展开的子菜单 allSubMenuBodies.forEach(body => body.classList.remove('active')); // 切换当前点击子菜单的状态 if (!isCurrentActive) { subMenuBody.classList.add('active'); } }) })
内容的提问来源于stack exchange,提问作者Matrion
相关产品推荐
相关产品推荐

