简体   繁体   English

jQuery多层手风琴菜单

[英]jQuery multi-level accordion menu

I found some accordion menus online but either they did not support multiple levels, or the code was quite cryptic and I didn't want to use it. 我在网上找到了一些手风琴菜单,但是它们要么不支持多个级别,要么代码很神秘,我不想使用它。 So I decided, that I want to write my own accordion menu, which supports an arbitrary number of sub-menus. 因此,我决定要编写自己的手风琴菜单,该菜单支持任意数量的子菜单。

Here is what I have so far: 这是我到目前为止的内容:

 $(document).ready(function() { // at the beginning only the top menu items are visible $('.multi-level-accordion-menu > li ul').slideUp(0); console.log('all elements slid up'); // when a menu item which is not active is clicked, show the next lower level // when a menu item which is active is clicked, hide all its sub menu items $('.multi-level-accordion-menu li').click(function() { var menu_item = $(this); if (is_active(menu_item)) { console.log('active menu item clicked'); close_menu_item(menu_item); } else { console.log('inactive menu item clicked'); open_menu_item(menu_item); } }); console.log('READY!'); }); function open_menu_item(menu_item) { menu_item.children('ul').slideDown(500); menu_item.addClass('active-menu-item'); } function close_menu_item(menu_item) { console.log('1x'); menu_item.find('ul').each(function(index, elem) { $(elem).slideUp(); return false; }); menu_item.removeClass('active-menu-item'); } function is_active(menu_item) { return menu_item.hasClass('active-menu-item'); } 
 .multi-level-accordion-menu * { margin: 0px; padding: 0px; } .multi-level-accordion-menu { list-style: none; max-width: 200px; } .multi-level-accordion-menu ul { list-style: none; } .multi-level-accordion-menu li { border-color: #EEEEEE; border-width: 1px; border-style: solid; background-color: #303030; margin: 2px; padding: 2px; line-height: 30px; font-size: 16px; } .multi-level-accordion-menu { color: #DDDDDD; } body { background-color: #202020; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <body> <div> <ul class='multi-level-accordion-menu'> <li>Item 1 <ul> <li>Item 1.1 <ul> <li>Item 1.1.1</li> <li>Item 1.1.2</li> <li>Item 1.1.3</li> <li>Item 1.1.4</li> </ul> </li> <li>Item 1.2</li> <li>Item 1.3</li> <li>Item 1.4</li> <li>Item 1.5</li> <li>Item 1.6</li> </ul> </li> <li>Item 2</li> <li>Item 3 <ul> <li>Item 3.1 <ul> <li>Item 3.1.1</li> <li>Item 3.1.2</li> <li>Item 3.1.3</li> <li>Item 3.1.4</li> </ul> </li> <li>Item 3.2</li> <li>Item 3.3</li> <li>Item 3.4</li> <li>Item 3.5</li> <li>Item 3.6</li> </ul> </li> <li>Item 4</li> <li>Item 5</li> <li>Item 6</li> <li>Item 7</li> </ul> </div> </body> 

http://jsfiddle.net/Zelphir/1fp03oyq/1/ http://jsfiddle.net/Zelphir/1fp03oyq/1/

Clicks on top level menu items work, but when I click Item 1 and then Item 1.1 it becomes obvious, that the lower levels don't work yet. 单击顶层菜单项会起作用,但是当我单击Item 1 Item 1.1然后再单击Item 1.1时,很明显,较低级别的菜单项仍不起作用。 The sub-menu opens but somehow at the same time the top level closes again. 子菜单打开,但同时又以某种方式再次关闭顶层菜单。

How can I achieve the following behavior: 如何实现以下行为:

  1. A click on an 'inactive' menu item makes its sub-menu items visible 单击“无效”菜单项将使其子菜单项可见
  2. A click on an 'active' menu item hides its sub menu items and their sub menu items 单击“活动”菜单项会隐藏其子菜单项及其子菜单项
  3. At the beginning all items are 'inactive' 一开始,所有项目都是“无效”的

This should work for you. 这应该为您工作。

$('.multi-level-accordion-menu').click(function(e){
    var menu_item = $(e.target);

    if(is_active(menu_item)) {
        console.log('active menu item clicked');
        close_menu_item(menu_item);

    } else {
        console.log('inactive menu item clicked');
        open_menu_item(menu_item);          
    }
});

function close_menu_item(menu_item) {
    console.log('1x');

    menu_item.find('ul').each(function() {
        $(this).slideUp().find('li').removeClass('active-menu-item');
    });

    menu_item.removeClass('active-menu-item');
}

Or a one/two liner 或一两个衬垫

function close_menu_item(menu_item) {
    console.log('1x');  

    menu_item.removeClass('active-menu-item').find('ul').slideUp().
    find('li').removeClass('active-menu-item');
}

In response to your comment: 针对您的评论:

In this case bubbling is what causes the 'click' method to fire on the outermost container (.multi-level-accordion-menu). 在这种情况下,起泡是导致“ click”方法在最外面的容器上触发的原因(.multi-level-accordion-menu)。

When you click on a child element, it is stored in the 'target' property of an 'event' object, and the click event bubbles up until it hits the outermost container, which you have defined in the jQuery selector( again - .multi-level-accordion-menu). 当您单击一个子元素时,该子元素将存储在“事件”对象的“目标”属性中,并且单击事件会冒泡直到其击中您在jQuery选择器中定义的最外面的容器(再次-.multi -level-accordion-menu)。

The outermost container is sitting there listening for 'click' events, so when this event bubbles up to it, it enters into the function. 最外面的容器坐在那里侦听“单击”事件,因此当该事件冒泡到它时,它将进入该函数。

You are then selecting the target element that triggered it all (stored in 'target' property of 'event' object) and performing whatever you want on it. 然后,您选择触发所有元素的目标元素(存储在“事件”对象的“目标”属性中)并对其执行所需的操作。 Since you are now inside the function and there are no event listeners in there, no more events fire, and thus there is no further bubbling. 由于您现在位于函数内部,并且那里没有事件侦听器,因此不会再触发任何事件,因此不会再冒泡了。 The function completes and no more 'click' events are triggered since the event has already bubbled to the top. 该功能完成,并且不再触发“点击”事件,因为该事件已经冒泡到顶部。

In your original code, you were listening for click events on all 'li' elements, so when you clicked on a 'li' element it would immediately trigger the click listener and then run your function. 在您的原始代码中,您正在侦听所有“ li”元素上的单击事件,因此,当您单击“ li”元素时,它将立即触发点击侦听器,然后运行您的函数。 Then when the function finished the event would bubble up to an ancestor 'li' element, trigger the listener again and run the method again. 然后,当函数完成时,事件将冒泡到一个祖先“ li”元素,再次触发侦听器并再次运行该方法。 And so on. 等等。

Hope this clears it up a bit! 希望这可以清除它!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM