JavaScript实现点击div外部时自动切换隐藏展开的菜单元素
点击菜单外部自动收起展开项实现方案
现有代码逻辑
当前已实现点击箭头按钮切换菜单收起/展开状态,核心代码如下:
切换函数
function replace( hide, show ) { document.getElementById(hide).style.display="none"; document.getElementById(show).style.display="flex"; }
样式代码
@import url('https://fonts.googleapis.com/css2?family=Allerta+Stencil&family=Bebas+Neue&family=Inter:wght@100;200;300;400;600;700;800&family=Roboto:wght@300;400;700&family=VT323&display=swap'); body { margin: 0; padding: 0; } .all_guidebook { width: 100%; position: absolute; min-height: 1000px; height: auto; display: flex; flex-direction: column; align-items: center; } .title_guidebook { position: relative; top: 50px; justify-content: center; } .disposition_guidebook { width: 1100px; display: flex; position: relative; align-items: flex-start; top: 55px; } .navigation { width: 286px; background: var(--bleu); position: relative; height: auto; padding-bottom: 30px; border-radius: 35px; margin-right: 15px; } .navigation .all_links { position: relative; top: 15px; } .navigation h1 { color: white; font: 45px 'Bebas Neue'; margin: 0; text-align: center; position: relative; top: 15px; } .navigation h2 { color: white; font: 34px 'Bebas Neue'; position: relative; background: var(--fushia); display: flex; border-radius: 15px; height: 45px; padding-top: 2px; margin-bottom: 26px !important; width: 247px; box-sizing: border-box; top: 20px; margin: auto; justify-content: center; } .navigation .menu_deroul, #regl { display: flex; background: blue; width: 300px; } #reglhover { display: flex; background: blue; width: 300px; } #reglhover img, #staffcredshover img, #ctxhover img, #grphover img, #pvrhover img, #syst1hover img, #syst2hover img, #pihover img, #exphover img, #foirehover img { transform: rotate(135deg); top: 5px; position: relative; left: 7px; } .navigation .menu_deroul img { float: left; left: 7px; position: relative; cursor: pointer; } .navigation span { color: var(--fushiapp); margin-right: 3px; font: 20px 'Bebas Neue'; } .navigation h3 { color: var(--white); font: 20px 'Bebas Neue'; } .wrap_deroul { display: flex; flex-direction: column; position: relative; top: -18px; align-items: flex-end; } .ancres_deroul { list-style: none; display: flex; flex-direction: column; align-items: flex-end; height: 30px; padding: 0; color: white; top: -16px; font-weight: 200!important; right: 16px; font: 16px 'Bebas Neue'; position: relative; } .ancres_deroul ul { margin: 0; display: flex; cursor: pointer; list-style: none; align-items: flex-end; flex-direction: column; } .ancres_deroul li {transition: .5s;} .ancres_deroul li a { text-decoration: none!important; color: black; } .ancres_deroul li:hover { letter-spacing: .5px; transition: .5s; }
HTML结构示例
<div class="menu_deroul" id="regl" style="display:flex" > <img src="https://i.ibb.co/cvhdX78/image.png" height="21" width="21" onclick="replace('regl','reglhover')" /> <div class="titre_deroul"> <span>001.</span> <h3 class="tablinks" onclick="openCity(event, 'reglement')" id="defaultOpen">Règlement</h3> </div> </div> <div id="reglhover" style="display:none"> <img src="https://i.ibb.co/cvhdX78/image.png" height="21" width="21" style="cursor:pointer; transform: rotate(135deg); transition: .5s; transition-duration: 2s;" onclick="replace('reglhover','regl')" /> <div class="wrap_deroul"> <div class="titre_deroul"> <span>001.</span> <h3 class="tablinks" onclick="openCity(event, 'reglement')">Règlement</h3> </div> <div class="ancres_deroul"> <ul> <li><a onclick="scrollWin()">Inscription & RP</a></li> <li style="margin-top: -5px;"><a href="reglement.html#discord" target="myIframe">Discord</a></li> </ul> </div> </div> </div>
需求
- 展开态菜单(如id为
reglhover的元素)显示时,点击菜单外任意区域自动收起菜单,切回收起态 - 逻辑需要适配所有同类tab菜单项,无需单独为每个菜单编写代码
实现步骤
- 统一元素标识
给所有收起态菜单添加统一类名collapsed-menu,所有展开态菜单添加统一类名expanded-menu。确保所有菜单遵循命名规则:收起态id为自定义名称,展开态id为收起态id加hover后缀(和现有regl/reglhover规则一致)。 - 添加全局点击监听
将以下代码加入页面脚本,无需修改原有replace函数即可实现需求:
document.addEventListener('click', function(e) { // 遍历所有当前显示的展开态菜单 document.querySelectorAll('.expanded-menu').forEach(expandedEl => { if (expandedEl.style.display === 'none') return; // 匹配对应的收起态元素 const collapsedId = expandedEl.id.replace('hover', ''); const collapsedEl = document.getElementById(collapsedId); if (!collapsedEl) return; // 点击位置不在展开菜单内、也不在对应收起触发区域内时,执行收起 if (!expandedEl.contains(e.target) && !collapsedEl.contains(e.target)) { replace(expandedEl.id, collapsedId); } }) })
逻辑说明
- 完全兼容原有点击箭头切换的交互,无冲突
- 自动适配所有符合命名规则的菜单项,新增菜单无需额外写监听逻辑
- 点击菜单内部内容不会误触发收起,交互符合常规使用习惯
内容的提问来源于stack exchange,提问作者Ally Nael
相关产品推荐
相关产品推荐

