jQuery 多级手风琴菜单
jQuery multi-level accordion menu
网上找了一些手风琴菜单,要么不支持多级,要么代码比较晦涩,不想用。所以我决定,我想写我自己的手风琴菜单,它支持任意数量的子菜单。
这是我目前的情况:
$(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/
点击顶级菜单项可以工作,但是当我点击 Item 1
然后 Item 1.1
时,很明显,较低的菜单项还没有工作。子菜单打开,但不知何故同时顶级菜单再次关闭。
如何实现以下行为:
- 单击 'inactive' 菜单项会使其子菜单项可见
- 单击 'active' 菜单项会隐藏其子菜单项及其子菜单项
- 一开始所有项目都是'inactive'
这应该适合你。
$('.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');
}
或 one/two 衬垫
function close_menu_item(menu_item) {
console.log('1x');
menu_item.removeClass('active-menu-item').find('ul').slideUp().
find('li').removeClass('active-menu-item');
}
回复您的评论:
在这种情况下,冒泡是导致 'click' 方法在最外层容器 (.multi-level-accordion-menu) 上触发的原因。
当你点击一个子元素时,它被存储在一个'event'对象的'target'属性中,点击事件向上冒泡,直到它到达最外层的容器,您在 jQuery 选择器中定义的(再次 - .multi-level-accordion-menu)。
最外面的容器坐在那里监听 'click' 事件,所以当这个事件冒泡到它时,它进入函数。
然后您选择触发它的目标元素(存储在 'event' 对象的 'target' 属性 中)并对其执行任何操作。
由于您现在位于函数内部并且那里没有事件侦听器,因此不会触发更多事件,因此不会再冒泡。函数完成,不再触发 'click' 个事件,因为事件已经冒泡到顶部。
在您的原始代码中,您正在监听所有 'li' 元素上的点击事件,因此当您点击 'li' 元素时,它会立即触发点击监听器,然后 运行 你的功能。
然后当函数完成时,事件将冒泡到祖先 'li' 元素,再次触发侦听器并再次 运行 方法。等等。
希望这能让事情更清楚一些!
网上找了一些手风琴菜单,要么不支持多级,要么代码比较晦涩,不想用。所以我决定,我想写我自己的手风琴菜单,它支持任意数量的子菜单。
这是我目前的情况:
$(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/
点击顶级菜单项可以工作,但是当我点击 Item 1
然后 Item 1.1
时,很明显,较低的菜单项还没有工作。子菜单打开,但不知何故同时顶级菜单再次关闭。
如何实现以下行为:
- 单击 'inactive' 菜单项会使其子菜单项可见
- 单击 'active' 菜单项会隐藏其子菜单项及其子菜单项
- 一开始所有项目都是'inactive'
这应该适合你。
$('.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');
}
或 one/two 衬垫
function close_menu_item(menu_item) {
console.log('1x');
menu_item.removeClass('active-menu-item').find('ul').slideUp().
find('li').removeClass('active-menu-item');
}
回复您的评论:
在这种情况下,冒泡是导致 'click' 方法在最外层容器 (.multi-level-accordion-menu) 上触发的原因。
当你点击一个子元素时,它被存储在一个'event'对象的'target'属性中,点击事件向上冒泡,直到它到达最外层的容器,您在 jQuery 选择器中定义的(再次 - .multi-level-accordion-menu)。
最外面的容器坐在那里监听 'click' 事件,所以当这个事件冒泡到它时,它进入函数。
然后您选择触发它的目标元素(存储在 'event' 对象的 'target' 属性 中)并对其执行任何操作。 由于您现在位于函数内部并且那里没有事件侦听器,因此不会触发更多事件,因此不会再冒泡。函数完成,不再触发 'click' 个事件,因为事件已经冒泡到顶部。
在您的原始代码中,您正在监听所有 'li' 元素上的点击事件,因此当您点击 'li' 元素时,它会立即触发点击监听器,然后 运行 你的功能。 然后当函数完成时,事件将冒泡到祖先 'li' 元素,再次触发侦听器并再次 运行 方法。等等。
希望这能让事情更清楚一些!