jQuery实现树形导航菜单点击时自动折叠非当前展开项
Hey there! Let's tackle this auto-collapse issue for your jQuery tree menu. Both of your ideas are totally solid—let's break down how to implement them step by step, integrating right into your existing code.
思路1:全局折叠所有其他展开项
This approach ensures that only the currently clicked (expanded) menu item stays open, and every other expanded branch gets collapsed. Perfect if you want a single open branch across the entire tree.
Here's how to modify your existing click handler:
$('#cssmenu > ul > li > ul > li > a').click(function() { sessionStorage.removeItem('secondChildMenu'); var parentEl = $(this).parent().parent().parent(); var parentElId = parentEl.children('a').attr('id'); saveParent(parentElId); let firstChildElement = $(this).attr('id'); var checkElement = $(this).next(); saveFirstChild(firstChildElement); $(this).closest('ul > li').addClass('active'); // 折叠当前项(如果已经展开) if ((checkElement.is('ul')) && (checkElement.is(':visible'))) { $(this).closest('li').removeClass('active'); checkElement.slideUp(100); checkElement.closest('li').addClass("has-sub").removeClass("menu-expanded"); } // 展开当前项并折叠其他所有展开项 if ((checkElement.is('ul')) && (!checkElement.is(':visible'))) { // 核心逻辑:找到所有展开项,排除当前项,逐个折叠 $('.menu-expanded').not($(this).closest('li')).each(function() { $(this).find('> ul').slideUp(100); $(this).removeClass('menu-expanded active').addClass('has-sub'); }); // 展开当前项 checkElement.slideDown(100); checkElement.closest('li').removeClass("has-sub").addClass("menu-expanded"); } return checkElement.is('ul') ? false : true; });
思路2:仅折叠同级展开项
If you want to allow expanded branches across different parent levels (e.g., keep a branch open under Menu 1 while expanding a branch under Menu 2), this approach only collapses siblings of the current clicked item.
Modify your click handler like this:
$('#cssmenu > ul > li > ul > li > a').click(function() { sessionStorage.removeItem('secondChildMenu'); var parentEl = $(this).parent().parent().parent(); var parentElId = parentEl.children('a').attr('id'); saveParent(parentElId); let firstChildElement = $(this).attr('id'); var checkElement = $(this).next(); saveFirstChild(firstChildElement); const currentLi = $(this).closest('ul > li'); currentLi.addClass('active'); // 折叠当前项(如果已经展开) if ((checkElement.is('ul')) && (checkElement.is(':visible'))) { currentLi.removeClass('active'); checkElement.slideUp(100); currentLi.addClass("has-sub").removeClass("menu-expanded"); } // 展开当前项并折叠同级展开项 if ((checkElement.is('ul')) && (!checkElement.is(':visible'))) { // 核心逻辑:找到当前项的所有同级li,折叠其中展开的项 currentLi.siblings('li').each(function() { if ($(this).hasClass('menu-expanded')) { $(this).find('> ul').slideUp(100); $(this).removeClass('menu-expanded active').addClass('has-sub'); } }); // 展开当前项 checkElement.slideDown(100); currentLi.removeClass("has-sub").addClass("menu-expanded"); } return checkElement.is('ul') ? false : true; });
后续优化:封装可复用函数
Since you plan to add support for 2nd/3rd level menus later, wrap the collapse logic into reusable functions to avoid duplicate code:
// 全局折叠所有展开项(排除指定项) function collapseAllExpanded(excludeLi) { $('.menu-expanded').not(excludeLi).each(function() { $(this).find('> ul').slideUp(100); $(this).removeClass('menu-expanded active').addClass('has-sub'); }); } // 折叠同级展开项 function collapseSiblingExpanded(currentLi) { currentLi.siblings('li').each(function() { if ($(this).hasClass('menu-expanded')) { $(this).find('> ul').slideUp(100); $(this).removeClass('menu-expanded active').addClass('has-sub'); } }); }
Then just call the function you need inside the expand block, like collapseAllExpanded(currentLi); or collapseSiblingExpanded(currentLi);.
Quick Menu Structure Reference
To visualize the hierarchy:
- Parent Menu 1 (has-sub/menu-expanded)
- Child Menu 1-1
- Child Menu 1-2 (has-sub/menu-expanded)
- Grandchild Menu 1-2-1
- Parent Menu 2 (has-sub)
- Child Menu 2-1
内容的提问来源于stack exchange,提问作者James

