如何在父li拥有has-menu类时阻止链接打开,同时保留多级菜单的折叠展开功能
解决多级菜单折叠展开与链接跳转的冲突问题
我明白你遇到的困扰:既要让带has-menu类的父菜单点击时只执行折叠展开,不能跳转链接;又要保证不带该类的子菜单链接能正常打开,同时不能破坏菜单的折叠功能。咱们来一步步修复这个问题:
问题根源
原来的代码给所有<li>绑定了点击事件,当点击has-menu类<li>里的链接时,事件会冒泡到父<li>,触发e.preventDefault()导致链接无法打开;而且折叠逻辑的触发范围太广,只要点到<li>的任何区域都会触发,很容易和链接点击产生冲突。
解决方案
核心思路是区分点击目标,给不同的点击区域分配不同的行为:
- 点击
<li>里的链接时:判断父<li>是否有has-menu类,有则阻止链接跳转,否则允许正常打开; - 点击
<li>的非链接区域(比如折叠符号、菜单文本)时:执行折叠展开逻辑,同时阻止事件冒泡避免影响上层菜单。
修改后的JavaScript代码如下:
$('li').click(function(e) { const $currentLi = $(this); // 判断点击的目标是不是a标签 if ($(e.target).is('a')) { // 父li带has-menu类,阻止链接跳转 if ($currentLi.hasClass('has-menu')) { e.preventDefault(); } // 不带has-menu类则不干预,让链接正常跳转 } else { // 点击的是非链接区域,执行折叠展开 if ($currentLi.hasClass('has-menu')) { e.stopPropagation(); // 阻止事件冒泡到上层菜单 $currentLi.find(".menu-wrapper > ul").toggleClass("menu-close"); $currentLi.toggleClass("menu-open"); } } });
代码细节说明
- 目标区分:通过
$(e.target).is('a')精准判断用户点击的是链接还是菜单的其他区域; - 链接逻辑:只有当链接的父
<li>没有has-menu类时,才允许正常跳转,完全符合需求中指定的可跳转链接规则; - 折叠优化:仅在点击非链接区域时触发折叠,同时用
e.stopPropagation()避免触发上层菜单的折叠事件,保证多级菜单的独立性。
完整可运行代码示例
<!DOCTYPE html> <html> <head> <style> ul{ padding: 0; list-style: none; } ul li{ padding: 5px 0; position: relative; padding-right: 20px; /* 给折叠符号留出空间,避免重叠 */ } ul li a{ width: 100%; display: inline-block; } .menu-close{ display: none; } /* Main menu */ .menu-main{ width: 250px; } .has-menu:before{ content: '+'; position: absolute; right: 0; cursor: pointer; /* 提示用户该区域可点击 */ } .has-menu.menu-open:before{ content: '-' !important; } </style> </head> <body> <ul class="menu-main"> <li class="has-menu"> Test 1 <div class="menu-wrapper"> <ul class="menu-child menu-close"> <li class="has-menu"> <a href="https://www.google.com" target="_blank">Sub cat 1/1</a> <div class="menu-wrapper"> <ul class="menu-subchild menu-close"> <li> <a href="https://www.google.com" target="_blank">Sub Sub cat 1/1</a> </li> </ul> </div> </li> </ul> <ul class="menu-child menu-close"> <li> <a href="https://www.google.com" target="_blank">Sub cat 1/2</a> </li> </ul> </div> </li> </ul> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script> $('li').click(function(e) { const $currentLi = $(this); if ($(e.target).is('a')) { if ($currentLi.hasClass('has-menu')) { e.preventDefault(); } } else { if ($currentLi.hasClass('has-menu')) { e.stopPropagation(); $currentLi.find(".menu-wrapper > ul").toggleClass("menu-close"); $currentLi.toggleClass("menu-open"); } } }); </script> </body> </html>
我还在CSS里加了一点小优化:给<li>增加右侧内边距避免文本和折叠符号重叠,给折叠符号加上指针光标提升交互体验。
内容的提问来源于stack exchange,提问作者user16462554
相关产品推荐
相关产品推荐

