首先,忽略CSS。它只是为了样式。
JS代码的作用:
- 当点击"菜单"或其中一个"+"时激活。
- 通过赋予自己"active"类,打开位于点击按钮("菜单"或"+")后的
ul
,然后CSS完成所有其余的工作(打开菜单并通过.dropdown-toggle.active + .toggleable
过渡,其中.toggleable
是ul
)。 - 查找同级别的任何打开的菜单,并在打开单击按钮的菜单之前关闭它们。
- 当按钮被点击关闭时,它首先依次关闭所有子按钮,从最深的打开按钮开始,最后关闭自己,以产生折叠一张纸的效果。
问题是,当我关闭一个菜单,deepset子将关闭,然后其余的将同时关闭在一起。我想让它们依次关闭。我使用transitionend
来检查子进程是否在关闭下一个父进程之前关闭,等等。
// Dropdown toggle click event fucntion.
$('.dropdown-toggle').on('click', function() {
if ($(this).is('.top-toggler:not(.active)')) { // If the top toggler "Menu" was clicked, and it wasn't ative, activate it, and return.
$(this).addClass('active');
return;
}
function closeToggleables(button, toggleable) { // Function to process what needs to be closed and close it.
var $activeChildren = toggleable.find('.dropdown-toggle.active'); // Get all active children dropdown buttons.
if ($activeChildren.length) { // If active children dropdown buttons exist, continue.
$.each($activeChildren, function(i, activeChild){ // Iterate through every active child button.
// Hook the ul menu next to the active child with a transitionend to close its parent after the transition ends (to close its parent when it is done closing).
$(activeChild).next('.toggleable').one('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function() { // The transitionend hook.
$(activeChild).parent().parent().prev('.active').removeClass('active'); // Close parent when transition ends.
});
});
$activeChildren.last().removeClass('active'); // Deactivate the last active button to begin closing from the deepest child to the passed parent.
} else {
button.removeClass('active'); // If there are no active children buttons, just deactivate this button to close its menu.
}
}
if ($(this).hasClass('active')) { // If the clicked button is active.
closeToggleables($(this), $(this).next('.toggleable')); // Send element and its menu to process how it will close.
} else { // If this menu button is inactive.
var $activeSibling = $(this).parent().siblings('.parent').children('.active'); // See if any siblings are open.
if ($activeSibling.length) { // If an open sibling exists.
closeToggleables($activeSibling, $activeSibling.next('.toggleable')); // Send the sibling to be processed to close first.
}
$(this).addClass('active'); // Activate this menu.
}
});
body {
font-family: lato, sans-serif;
font-size: 1em;
line-height: 1.5;
color: #2c3e50;
}
a {
text-decoration: none;
}
.text-center {
text-align: center;
}
.hide {
visibility: hidden;
overflow: hidden;
max-height: 0;
}
.dropdown-toggle {
line-height: inherit;
padding: 12px;
color: #ecf0f1;
outline: 0;
}
.dropdown-toggle.active {
color: #fbfcfc;
background: #ea6153;
}
.toggleable {
-webkit-transition: max-height .75s ease-in-out, -webkit-transform .75s ease-in-out, visibility .75s ease-in-out;
transition: max-height .75s ease-in-out, transform .75s ease-in-out, visibility .75s ease-in-out;
-webkit-transform: scaleY(0);
transform: scaleY(0);
-webkit-transform-origin: top;
transform-origin: top;
}
.toggleable .toggleable {
-webkit-transform: scaleY(1);
transform: scaleY(1);
-webkit-transform-origin: center;
transform-origin: center;
}
.dropdown-toggle.active + .toggleable {
visibility: visible;
max-height: 1200px;
-webkit-transform: scaleY(1);
transform: scaleY(1);
}
ul {
margin: 0;
padding: 0;
list-style-type: none;
}
button {
font-family: lato, sans-serif;
font-size: 1em;
padding: .75em 1.5em;
-webkit-transition: background-color .75s ease;
transition: background-color .75s ease;
vertical-align: middle;
color: #ecf0f1;
border: 0;
border-radius: 3px;
background-color: #e74c3c;
}
button:focus,
button:hover {
color: #fbfcfc;
background-color: #ea6153;
}
#nav-primary {
position: relative;
margin: 30px 10px;
}
#nav-primary .dropdown-toggle.active + .toggleable > .menu-item {
margin: 0;
-webkit-transform: perspective(320px) rotateX(0deg);
transform: perspective(320px) rotateX(0deg);
box-shadow: inset 0 0 20px 0 transparent;
}
#menu-main-toggle {
width: 100%;
border-radius: 0;
}
#menu-main {
position: absolute;
width: 100%;
}
#menu-main .menu-item {
-webkit-transition: -webkit-transform .75s ease-in-out, margin .75s ease-in-out, -webkit-box-shadow .75s ease-in-out;
transition: transform .75s ease-in-out, margin .75s ease-in-out, box-shadow .75s ease-in-out;
background: #e74c3c;
}
#menu-main .menu-item.odd {
margin-bottom: -100px;
-webkit-transform: perspective(320px) rotateX(-90deg);
transform: perspective(320px) rotateX(-90deg);
-webkit-transform-origin: top;
transform-origin: top;
box-shadow: inset 0 -50px 25px 0 rgba(0, 0, 0, .5);
}
#menu-main .menu-item.even {
margin-top: -100px;
-webkit-transform: perspective(320px) rotateX(90deg);
transform: perspective(320px) rotateX(90deg);
-webkit-transform-origin: bottom;
transform-origin: bottom;
box-shadow: inset 0 50px 25px 0 rgba(0, 0, 0, .5);
}
#menu-main .menu-link {
display: inline-block;
width: 100%;
height: 50px;
padding: 12px;
color: #ecf0f1;
border-top: 1px dashed #bf2718;
box-sizing: border-box;
}
#menu-main .parent .dropdown-toggle.active + .toggleable > .menu-item {
margin: 0 5px;
}
#menu-main .parent .dropdown-toggle.active + .toggleable > .menu-item.last {
margin-bottom: 5px;
}
#menu-main .parent > .menu-link {
margin-right: -54px;
}
#menu-main .dropdown-toggle {
width: 50px;
height: 48px;
vertical-align: bottom;
border-radius: 0;
background: transparent;
}
#menu-main .toggleable {
background: #bf2718;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.min.css" rel="stylesheet"/>
<nav id="nav-primary" class="text-center">
<button id="menu-main-toggle" class="top-toggler dropdown-toggle">Menu</button>
<ul id="menu-main" class="toggleable hide">
<li class="menu-item odd">
<a class="menu-link" href="http://example.com/">About</a>
</li>
<li class="menu-item even">
<a class="menu-link" href="http://example.com/">Something</a>
</li>
<li class="menu-item odd parent">
<a class="menu-link" href="http://example.com/">Information Technology</a>
<button class="dropdown-toggle">+</button>
<ul class="toggleable hide">
<li class="menu-item odd parent">
<a class="menu-link" href="http://example.com/">Web Development</a>
<button class="dropdown-toggle">+</button>
<ul class="toggleable hide">
<li class="menu-item odd">
<a class="menu-link" href="http://example.com/">HTML</a>
</li>
<li class="menu-item even">
<a class="menu-link" href="http://example.com/">CSS</a>
</li>
<li class="menu-item odd last">
<a class="menu-link" href="http://example.com/">Javascript</a>
</li>
</ul>
</li>
<li class="menu-item even last">
<a class="menu-link" href="http://example.com/">Unix</a>
</li>
</ul>
</li>
<li class="menu-item even parent">
<a class="menu-link" href="http://example.com/">Level One</a>
<button class="dropdown-toggle">+</button>
<ul class="toggleable hide">
<li class="menu-item odd last parent">
<a class="menu-link" href="http://example.com/">Level Two</a>
<button class="dropdown-toggle">+</button>
<ul class="toggleable hide">
<li class="menu-item odd last parent">
<a class="menu-link" href="http://example.com/">Level Three</a>
<button class="dropdown-toggle">+</button>
<ul class="toggleable hide">
<li class="menu-item odd last parent">
<a class="menu-link" href="http://example.com/">Lorem</a>
<button class="dropdown-toggle script-dependant">+</button>
<ul class="toggleable hide">
<li class="menu-item odd parent">
<a class="menu-link" href="http://example.com/">Ipsum</a>
<button class="dropdown-toggle script-dependant">+</button>
<ul class="toggleable hide">
<li class="menu-item odd last">
<a class="menu-link" href="http://example.com/">Dolor</a>
</li>
</ul>
</li>
<li class="menu-item even last">
<a class="menu-link" href="http://example.com/">Situs</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="menu-item odd">
<a class="menu-link" href="http://example.com/">Snippets</a>
</li>
<li class="menu-item even last">
<a class="menu-link" href="http://example.com/">Contact</a>
</li>
</ul>
</nav>
由于元素上有多个属性过渡,因此每当调用transitionend时,我只检查元素的高度。一旦高度为零,我就解除事件的绑定并切换父按钮。
// Dropdown toggle click event fucntion.
$('.dropdown-toggle').on('click', function() {
// If dropdown-toggle is an inactive top toggler, activate.
if ($(this).is('.top-toggler:not(.active)')) {
$(this).addClass('active');
return;
}
// Function to process how to close toggleables; either children first, or just the clicked toggleable.
function closeToggleables(button, toggleable) {
// Find all active children and turn them into an array.
var $activeChildren = toggleable.find('.dropdown-toggle.active');
// If active children exist.
if ($activeChildren.length) {
// Iterate through each active child.
$activeChildren.each( function(){
// Bind child's menu to activate function when CSS transition ends.
$(this).next('.toggleable').on('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function(event) {
// Since many transitions occur, we check if the height transition ended by checking the height of the child's menu.
if ($(this).height() === 0) {
// Unbind event and deactivate parent of child.
$(this).off(event).parent().parent().prev('.active').removeClass('active');
}
});
});
// Deactivate last child to start deactivating all parents up to clicked element.
$activeChildren.last().removeClass('active');
} else {
// Deactivate clicked button.
button.removeClass('active');
}
}
// If button is active.
if ($(this).hasClass('active')) {
// Send button and its menu to be processed for closing.
closeToggleables($(this), $(this).next('.toggleable'));
} else {
// Check for an open sibling.
var $activeSibling = $(this).parent().siblings('.parent').children('.active');
// If an open sibling exists.
if ($activeSibling.length) {
// Send sibling and its menu to be processed for closing.
closeToggleables($activeSibling, $activeSibling.next('.toggleable'));
}
// Activate inactive button.
$(this).addClass('active');
}
});
body {
font-family: lato, sans-serif;
font-size: 1em;
line-height: 1.5;
color: #2c3e50;
}
a {
text-decoration: none;
}
.text-center {
text-align: center;
}
.hide {
visibility: hidden;
overflow: hidden;
max-height: 0;
}
.dropdown-toggle {
line-height: inherit;
padding: 12px;
color: #ecf0f1;
outline: 0;
}
.dropdown-toggle.active {
color: #fbfcfc;
background: #ea6153;
}
.toggleable {
-webkit-transition: max-height .75s ease-in-out, -webkit-transform .75s ease-in-out, visibility .75s ease-in-out;
transition: max-height .75s ease-in-out, transform .75s ease-in-out, visibility .75s ease-in-out;
-webkit-transform: scaleY(0);
transform: scaleY(0);
-webkit-transform-origin: top;
transform-origin: top;
}
.toggleable .toggleable {
-webkit-transform: scaleY(1);
transform: scaleY(1);
-webkit-transform-origin: center;
transform-origin: center;
}
.dropdown-toggle.active + .toggleable {
visibility: visible;
max-height: 1200px;
-webkit-transform: scaleY(1);
transform: scaleY(1);
}
ul {
margin: 0;
padding: 0;
list-style-type: none;
}
button {
font-family: lato, sans-serif;
font-size: 1em;
padding: .75em 1.5em;
-webkit-transition: background-color .75s ease;
transition: background-color .75s ease;
vertical-align: middle;
color: #ecf0f1;
border: 0;
border-radius: 3px;
background-color: #e74c3c;
}
button:focus,
button:hover {
color: #fbfcfc;
background-color: #ea6153;
}
#nav-primary {
position: relative;
margin: 30px 10px;
}
#nav-primary .dropdown-toggle.active + .toggleable > .menu-item {
margin: 0;
-webkit-transform: perspective(320px) rotateX(0deg);
transform: perspective(320px) rotateX(0deg);
box-shadow: inset 0 0 20px 0 transparent;
}
#menu-main-toggle {
width: 100%;
border-radius: 0;
}
#menu-main {
position: absolute;
width: 100%;
}
#menu-main .menu-item {
-webkit-transition: -webkit-transform .75s ease-in-out, margin .75s ease-in-out, -webkit-box-shadow .75s ease-in-out;
transition: transform .75s ease-in-out, margin .75s ease-in-out, box-shadow .75s ease-in-out;
background: #e74c3c;
}
#menu-main .menu-item.odd {
margin-bottom: -100px;
-webkit-transform: perspective(320px) rotateX(-90deg);
transform: perspective(320px) rotateX(-90deg);
-webkit-transform-origin: top;
transform-origin: top;
box-shadow: inset 0 -50px 25px 0 rgba(0, 0, 0, .5);
}
#menu-main .menu-item.even {
margin-top: -100px;
-webkit-transform: perspective(320px) rotateX(90deg);
transform: perspective(320px) rotateX(90deg);
-webkit-transform-origin: bottom;
transform-origin: bottom;
box-shadow: inset 0 50px 25px 0 rgba(0, 0, 0, .5);
}
#menu-main .menu-link {
display: inline-block;
width: 100%;
height: 50px;
padding: 12px;
color: #ecf0f1;
border-top: 1px dashed #bf2718;
box-sizing: border-box;
}
#menu-main .parent .dropdown-toggle.active + .toggleable > .menu-item {
margin: 0 5px;
}
#menu-main .parent .dropdown-toggle.active + .toggleable > .menu-item.last {
margin-bottom: 5px;
}
#menu-main .parent > .menu-link {
margin-right: -54px;
}
#menu-main .dropdown-toggle {
width: 50px;
height: 48px;
vertical-align: bottom;
border-radius: 0;
background: transparent;
}
#menu-main .toggleable {
background: #bf2718;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.min.css" rel="stylesheet"/>
<nav id="nav-primary" class="text-center">
<button id="menu-main-toggle" class="top-toggler dropdown-toggle">Menu</button>
<ul id="menu-main" class="toggleable hide">
<li class="menu-item odd">
<a class="menu-link" href="http://example.com/">About</a>
</li>
<li class="menu-item even">
<a class="menu-link" href="http://example.com/">Something</a>
</li>
<li class="menu-item odd parent">
<a class="menu-link" href="http://example.com/">Information Technology</a>
<button class="dropdown-toggle">+</button>
<ul class="toggleable hide">
<li class="menu-item odd parent">
<a class="menu-link" href="http://example.com/">Web Development</a>
<button class="dropdown-toggle">+</button>
<ul class="toggleable hide">
<li class="menu-item odd">
<a class="menu-link" href="http://example.com/">HTML</a>
</li>
<li class="menu-item even">
<a class="menu-link" href="http://example.com/">CSS</a>
</li>
<li class="menu-item odd last">
<a class="menu-link" href="http://example.com/">Javascript</a>
</li>
</ul>
</li>
<li class="menu-item even last">
<a class="menu-link" href="http://example.com/">Unix</a>
</li>
</ul>
</li>
<li class="menu-item even parent">
<a class="menu-link" href="http://example.com/">Level One</a>
<button class="dropdown-toggle">+</button>
<ul class="toggleable hide">
<li class="menu-item odd last parent">
<a class="menu-link" href="http://example.com/">Level Two</a>
<button class="dropdown-toggle">+</button>
<ul class="toggleable hide">
<li class="menu-item odd last parent">
<a class="menu-link" href="http://example.com/">Level Three</a>
<button class="dropdown-toggle">+</button>
<ul class="toggleable hide">
<li class="menu-item odd last parent">
<a class="menu-link" href="http://example.com/">Lorem</a>
<button class="dropdown-toggle script-dependant">+</button>
<ul class="toggleable hide">
<li class="menu-item odd parent">
<a class="menu-link" href="http://example.com/">Ipsum</a>
<button class="dropdown-toggle script-dependant">+</button>
<ul class="toggleable hide">
<li class="menu-item odd last">
<a class="menu-link" href="http://example.com/">Dolor</a>
</li>
</ul>
</li>
<li class="menu-item even last">
<a class="menu-link" href="http://example.com/">Situs</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="menu-item odd">
<a class="menu-link" href="http://example.com/">Snippets</a>
</li>
<li class="menu-item even last">
<a class="menu-link" href="http://example.com/">Contact</a>
</li>
</ul>
</nav>