jQuery垂直侧边栏菜单搜索过滤功能异常及子菜单展开问题排查
解决Bootstrap垂直侧边栏菜单的搜索过滤问题
针对你提到的两个痛点——不匹配的子项无法隐藏、匹配子项的父菜单始终收起,我整理了一套修复方案,咱们一步步来调整:
问题根源分析
- 初始代码的问题:遍历所有
<li>时,仅根据当前<li>是否匹配关键词来控制其子元素的显示/隐藏,但父<li>匹配时,不匹配的子<li>没有被单独处理,导致无关项残留。 - 修改后代码的问题:仅给匹配
<li>的直接父<ul>加in类,没有处理深层嵌套的祖先菜单,而且单条<li>的判断逻辑容易导致父菜单展开状态混乱。
完整解决方案代码
$(document).ready(function () { // 保存菜单初始状态,清空搜索时恢复原样 const initialMenuState = { menuItems: $("nav li:not(.sidebar-search)").clone(), subMenuStates: $("nav ul:not(.nav)").map(function() { return $(this).hasClass("in"); }).get() }; $("#search").keyup(function () { const filter = $(this).val().trim(); const $allMenuItems = $("nav li:not(.sidebar-search)"); const $allSubMenus = $("nav ul:not(.nav)"); // 清空搜索框时,恢复菜单初始状态 if (filter === "") { $allMenuItems.replaceWith(initialMenuState.menuItems.clone()); $allSubMenus.each(function(index) { initialMenuState.subMenuStates[index] ? $(this).addClass("in") : $(this).removeClass("in"); }); return; } // 先统一隐藏所有菜单项,收起所有子菜单 $allMenuItems.hide(); $allSubMenus.removeClass("in"); // 筛选出所有包含关键词的菜单项 const $matchedItems = $allMenuItems.filter(function() { return $(this).text().toLowerCase().includes(filter.toLowerCase()); }); // 显示匹配的菜单项 $matchedItems.show(); // 处理匹配项的所有祖先:显示祖先菜单项,并展开对应的子菜单 $matchedItems.each(function() { $(this).parents("li:not(.sidebar-search)").each(function() { $(this).show(); // 给当前祖先li下的直接子ul添加in类,展开子菜单 $(this).children("ul").addClass("in"); }); }); }); });
关键逻辑说明
- 保存初始状态:页面加载时克隆所有菜单项和子菜单的展开状态,确保清空搜索时能完全恢复到初始样子,避免状态混乱。
- 统一初始化过滤状态:每次搜索时先隐藏所有菜单项、收起所有子菜单,再逐步恢复匹配项和其祖先,彻底解决不匹配子项残留的问题。
- 递归处理祖先菜单:找到匹配项后,遍历它的所有祖先
<li>,显示这些祖先并展开它们的直接子菜单,确保整个匹配分支都处于展开可见状态。
这样调整后,搜索"loo"时,不匹配的"Customer map"会被隐藏,而包含匹配子项的父菜单会自动展开,完美解决你遇到的两个问题。
内容的提问来源于stack exchange,提问作者Patrick Simard
相关产品推荐
相关产品推荐

