最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why must I click twice to open and close my menu - Stack Overflow

programmeradmin1浏览0评论

Hello I got a situation which I do not understand quite well. I have the following setup:

	$(document).ready(function(){
  $('.menuBtn').on('click touch', function () {
		$(this).toggleClass('act');
			if($(this).hasClass('act')) {
				$('.mobileMenu').addClass('act');
				//$('body').addClass('positionfixed');
			}
			else {
				$('.mobileMenu').removeClass('act');
				//$('body').removeClass('positionfixed');
			}
	});
  	});
	.mobile-menu-button{
		display:block;
		position:fixed;
		top:20px;
		left:20px;		
		z-index:99;
    background-color:#19b698;
    padding:5px 10px;
    color:#fff;
    font-family: Open Sans;
    font-weight:bold;
	}
	.mobile-menu-button i{
		font-size:26px;
		background-color:#00adee;
		padding:5px 10px;
		color:#fff;
	}
.mobileMenu {
		background-color: #fff !important;
		position: fixed;
		left: 0;
		top: 0;
		z-index: 100;	  
		height: 100vh;
		width: 100vw;
		display: block;
		text-align: center;
		opacity: 0;
		-webkit-transition: all 500ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
		transition: all 500ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
		-webkit-transform: scale(0);
			  transform: scale(0);
		overflow:hidden;
	}
	.mobileMenu img{
		max-width:90%;
		margin:0 auto;
		margin-top:20px;
		margin-bottom:10px;
		border-bottom:1px dotted #717274;
		padding-bottom:20px;
	}
	.mobileMenu.act {
		opacity: 1;
		-webkit-transform: scale(1);
			  transform: scale(1);
	}
	.mobileMenu.act ul li {
		opacity: 1;
		-webkit-transform: translateX(0);
			  transform: translateX(0);
		display:block !important;
	}
	.mobileMenu ul {
		display: block;
		vertical-align: middle;
	}
	.mobileMenu li {
		padding: 10px 0 !important;
		-webkit-transition: all 400ms 510ms;
		transition: all 400ms 510ms;
		opacity: 0;
	}
	.mobileMenu li:nth-child(odd) {
	  -webkit-transform: translateX(30%);
			  transform: translateX(30%);
	}
	.mobileMenu li:nth-child(even) {
	  -webkit-transform: translateX(-30%);
			  transform: translateX(-30%);
	}
	.mobileMenu li:last-child {
	  -webkit-transform: none;
			  transform: none;
	}
	.mobileMenu a {
	  color: #00adee !important;
	  display: inline-block;
	  font-size: 18px;
	}
	.mobileMenu a.suBtn {
	  color: #fff;
	}
<script src=".1.1/jquery.min.js"></script>
<span class="mobile-menu-button menuBtn">Open</span>
  <nav class="mobileMenu">
  <span class="mobile-menu-button menuBtn">Close</span>						
  <ul>
    <li><a href="index.html">Home</a></li>
    <li><a href="testimonials.html">Testimonials</a></li>
    <li><a href="contact.html">Contact</a></li>
  </ul>
</nav>

Hello I got a situation which I do not understand quite well. I have the following setup:

	$(document).ready(function(){
  $('.menuBtn').on('click touch', function () {
		$(this).toggleClass('act');
			if($(this).hasClass('act')) {
				$('.mobileMenu').addClass('act');
				//$('body').addClass('positionfixed');
			}
			else {
				$('.mobileMenu').removeClass('act');
				//$('body').removeClass('positionfixed');
			}
	});
  	});
	.mobile-menu-button{
		display:block;
		position:fixed;
		top:20px;
		left:20px;		
		z-index:99;
    background-color:#19b698;
    padding:5px 10px;
    color:#fff;
    font-family: Open Sans;
    font-weight:bold;
	}
	.mobile-menu-button i{
		font-size:26px;
		background-color:#00adee;
		padding:5px 10px;
		color:#fff;
	}
.mobileMenu {
		background-color: #fff !important;
		position: fixed;
		left: 0;
		top: 0;
		z-index: 100;	  
		height: 100vh;
		width: 100vw;
		display: block;
		text-align: center;
		opacity: 0;
		-webkit-transition: all 500ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
		transition: all 500ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
		-webkit-transform: scale(0);
			  transform: scale(0);
		overflow:hidden;
	}
	.mobileMenu img{
		max-width:90%;
		margin:0 auto;
		margin-top:20px;
		margin-bottom:10px;
		border-bottom:1px dotted #717274;
		padding-bottom:20px;
	}
	.mobileMenu.act {
		opacity: 1;
		-webkit-transform: scale(1);
			  transform: scale(1);
	}
	.mobileMenu.act ul li {
		opacity: 1;
		-webkit-transform: translateX(0);
			  transform: translateX(0);
		display:block !important;
	}
	.mobileMenu ul {
		display: block;
		vertical-align: middle;
	}
	.mobileMenu li {
		padding: 10px 0 !important;
		-webkit-transition: all 400ms 510ms;
		transition: all 400ms 510ms;
		opacity: 0;
	}
	.mobileMenu li:nth-child(odd) {
	  -webkit-transform: translateX(30%);
			  transform: translateX(30%);
	}
	.mobileMenu li:nth-child(even) {
	  -webkit-transform: translateX(-30%);
			  transform: translateX(-30%);
	}
	.mobileMenu li:last-child {
	  -webkit-transform: none;
			  transform: none;
	}
	.mobileMenu a {
	  color: #00adee !important;
	  display: inline-block;
	  font-size: 18px;
	}
	.mobileMenu a.suBtn {
	  color: #fff;
	}
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="mobile-menu-button menuBtn">Open</span>
  <nav class="mobileMenu">
  <span class="mobile-menu-button menuBtn">Close</span>						
  <ul>
    <li><a href="index.html">Home</a></li>
    <li><a href="testimonials.html">Testimonials</a></li>
    <li><a href="contact.html">Contact</a></li>
  </ul>
</nav>

Why should I press two times on the open / close button to open / close the menu?

Anyone any idea / fix?

Share Improve this question asked Mar 31, 2017 at 13:34 Rotan075Rotan075 2,6155 gold badges37 silver badges56 bronze badges 2
  • Have you tried adding evt.preventDefault(); maybe that's the case? – user218046 Commented Mar 31, 2017 at 13:36
  • 1 You can use .add rather than checking if the class has the value after toggle and applying it elsewhere: $(this).add('.mobileMenu').toggleClass('act'); – fdomn-m Commented Mar 31, 2017 at 13:45
Add a ment  | 

6 Answers 6

Reset to default 6

The problem is that you checking for .act on the button instead of the menu. There are two buttons so you need to toggle twice.

Changing:

$(this).toggleClass('act');
if($(this).hasClass('act')) {

to

$('.mobileMenu').toggleClass('act');
if($('.mobileMenu').hasClass('act')) {

fixes it:

	$(document).ready(function(){
  $('.menuBtn').on('click touch', function () {
		$('.mobileMenu').toggleClass('act');
			if($('.mobileMenu').hasClass('act')) {
				$('.mobileMenu').addClass('act');
				//$('body').addClass('positionfixed');
			}
			else {
				$('.mobileMenu').removeClass('act');
				//$('body').removeClass('positionfixed');
			}
	});
  	});
	.mobile-menu-button{
		display:block;
		position:fixed;
		top:20px;
		left:20px;		
		z-index:99;
    background-color:#19b698;
    padding:5px 10px;
    color:#fff;
    font-family: Open Sans;
    font-weight:bold;
	}
	.mobile-menu-button i{
		font-size:26px;
		background-color:#00adee;
		padding:5px 10px;
		color:#fff;
	}
.mobileMenu {
		background-color: #fff !important;
		position: fixed;
		left: 0;
		top: 0;
		z-index: 100;	  
		height: 100vh;
		width: 100vw;
		display: block;
		text-align: center;
		opacity: 0;
		-webkit-transition: all 500ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
		transition: all 500ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
		-webkit-transform: scale(0);
			  transform: scale(0);
		overflow:hidden;
	}
	.mobileMenu img{
		max-width:90%;
		margin:0 auto;
		margin-top:20px;
		margin-bottom:10px;
		border-bottom:1px dotted #717274;
		padding-bottom:20px;
	}
	.mobileMenu.act {
		opacity: 1;
		-webkit-transform: scale(1);
			  transform: scale(1);
	}
	.mobileMenu.act ul li {
		opacity: 1;
		-webkit-transform: translateX(0);
			  transform: translateX(0);
		display:block !important;
	}
	.mobileMenu ul {
		display: block;
		vertical-align: middle;
	}
	.mobileMenu li {
		padding: 10px 0 !important;
		-webkit-transition: all 400ms 510ms;
		transition: all 400ms 510ms;
		opacity: 0;
	}
	.mobileMenu li:nth-child(odd) {
	  -webkit-transform: translateX(30%);
			  transform: translateX(30%);
	}
	.mobileMenu li:nth-child(even) {
	  -webkit-transform: translateX(-30%);
			  transform: translateX(-30%);
	}
	.mobileMenu li:last-child {
	  -webkit-transform: none;
			  transform: none;
	}
	.mobileMenu a {
	  color: #00adee !important;
	  display: inline-block;
	  font-size: 18px;
	}
	.mobileMenu a.suBtn {
	  color: #fff;
	}
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="mobile-menu-button menuBtn">Open</span>
  <nav class="mobileMenu">
  <span class="mobile-menu-button menuBtn">Close</span>						
  <ul>
    <li><a href="index.html">Home</a></li>
    <li><a href="testimonials.html">Testimonials</a></li>
    <li><a href="contact.html">Contact</a></li>
  </ul>
</nav>

May I offer a solution where you have a single button controlling the display of the menu instead of two buttons?

Main changes were to increase the z-index of .mobile-menu-button so it's always on top of your menu and to check in the text value of the button and decide whether to open or close it. You could also check if the menu has .act on it instead of checking the text of the button; tomayto, tomahto.

$( document ).ready( function () {
  
  var $mobileMenu = $( '.mobileMenu' );

  $('.menuBtn').on( 'click touch', function () {
  
    var $this = $( this ),
        isOpen = 'Close' === $this.text();
        
    $this.text( isOpen ? 'Open' : 'Close' );
    $mobileMenu.toggleClass( 'act', !isOpen );
    
  } );
  
} );
.mobile-menu-button {
  display: block;
  position: fixed;
  top: 20px;
  left: 20px;
  z-index: 105;
  background-color: #19b698;
  padding: 5px 10px;
  color: #fff;
  font-family: Open Sans;
  font-weight: bold;
  cursor: pointer;
}

.mobile-menu-button i {
  font-size: 26px;
  background-color: #00adee;
  padding: 5px 10px;
  color: #fff;
}

.mobileMenu {
  background-color: #fff !important;
  position: fixed;
  left: 0;
  top: 0;
  z-index: 100;
  height: 100vh;
  width: 100vw;
  display: block;
  text-align: center;
  opacity: 0;
  -webkit-transition: all 500ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
  transition: all 500ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
  -webkit-transform: scale(0);
  transform: scale(0);
  overflow: hidden;
}

.mobileMenu img {
  max-width: 90%;
  margin: 0 auto;
  margin-top: 20px;
  margin-bottom: 10px;
  border-bottom: 1px dotted #717274;
  padding-bottom: 20px;
}

.mobileMenu.act {
  opacity: 1;
  -webkit-transform: scale(1);
  transform: scale(1);
}

.mobileMenu.act ul li {
  opacity: 1;
  -webkit-transform: translateX(0);
  transform: translateX(0);
  display: block !important;
}

.mobileMenu ul {
  display: block;
  list-style: none;
}

.mobileMenu li {
  padding: 10px 0 !important;
  -webkit-transition: all 400ms 510ms;
  transition: all 400ms 510ms;
  opacity: 0;
}

.mobileMenu li:nth-child(odd) {
  -webkit-transform: translateX(30%);
  transform: translateX(30%);
}

.mobileMenu li:nth-child(even) {
  -webkit-transform: translateX(-30%);
  transform: translateX(-30%);
}

.mobileMenu li:last-child {
  -webkit-transform: none;
  transform: none;
}

.mobileMenu a {
  color: #00adee !important;
  display: inline-block;
  font-size: 18px;
}

.mobileMenu a.suBtn {
  color: #fff;
}
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="mobile-menu-button menuBtn">Open</span>
<nav class="mobileMenu">
  <ul>
    <li><a href="index.html">Home</a></li>
    <li><a href="testimonials.html">Testimonials</a></li>
    <li><a href="contact.html">Contact</a></li>
  </ul>
</nav>

I also added list-style: none; to .mobileMenu ul as I noticed some bullet points. I'm assuming you didn't want those.


Why Two Clicks?

As far as why you had to click twice, you were using toggleClass() on two different buttons to open/close the menu. The first button (Open) would get .act added and the menu would show. Now we're seeing the second button (Close) which doesn't have .act yet, so you click it and toggleClass() adds .act to it (instead of removing .act from the first button (Open) like you might have been expecting). Since a button needs .act on it to hide the menu, you now need to click the second button (Close) a second time to for toggelClass() to remove .act and hide the menu. Now the first button (Open) is shown, which still has .act. But clicking it removes .act, thus necessitating one more click to add .act back to the button and now the menu can be show because the button has .act.

It's more simple to use a single button.

You should use below jQuery code instead of using yours::

$(document).ready(function(){
  $('.menuBtn').on('click touch', function () {
    $(this).toggleClass('act');
    if(!$('.mobileMenu').hasClass('act')) {
      $('.mobileMenu').addClass('act');
      //$('body').addClass('positionfixed');
    }
    else {
      $('.mobileMenu').removeClass('act');
      //$('body').removeClass('positionfixed');
    }
  });
});

Working URL:: https://jsfiddle/Lxz9v34L/2/

You have 2 .menuBtn. You could simplify your code to something like this:

$(document).ready(function(){
  $('.menuBtn').on('click touch', function () {
    $('.mobileMenu').toggleClass('act');
    $(this).text($(this).text() === 'Open' ? 'Close' : 'Open')
	});
});
.mobile-menu-button{
		display:block;
		position:fixed;
		top:20px;
		left:20px;		
		z-index:101;
    background-color:#19b698;
    padding:5px 10px;
    color:#fff;
    font-family: Open Sans;
    font-weight:bold;
    cursor: pointer;
	}
	.mobile-menu-button i{
		font-size:26px;
		background-color:#00adee;
		padding:5px 10px;
		color:#fff;
	}
.mobileMenu {
		background-color: #fff !important;
		position: fixed;
		left: 0;
		top: 0;
		z-index: 100;	  
		height: 100vh;
		width: 100vw;
		display: block;
		text-align: center;
		opacity: 0;
		-webkit-transition: all 500ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
		transition: all 500ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
		-webkit-transform: scale(0);
			  transform: scale(0);
		overflow:hidden;
	}
	.mobileMenu img{
		max-width:90%;
		margin:0 auto;
		margin-top:20px;
		margin-bottom:10px;
		border-bottom:1px dotted #717274;
		padding-bottom:20px;
	}
	.mobileMenu.act {
		opacity: 1;
		-webkit-transform: scale(1);
			  transform: scale(1);
	}
	.mobileMenu.act ul li {
		opacity: 1;
		-webkit-transform: translateX(0);
			  transform: translateX(0);
		display:block !important;
	}
	.mobileMenu ul {
		display: block;
		vertical-align: middle;
	}
	.mobileMenu li {
		padding: 10px 0 !important;
		-webkit-transition: all 400ms 510ms;
		transition: all 400ms 510ms;
		opacity: 0;
	}
	.mobileMenu li:nth-child(odd) {
	  -webkit-transform: translateX(30%);
			  transform: translateX(30%);
	}
	.mobileMenu li:nth-child(even) {
	  -webkit-transform: translateX(-30%);
			  transform: translateX(-30%);
	}
	.mobileMenu li:last-child {
	  -webkit-transform: none;
			  transform: none;
	}
	.mobileMenu a {
	  color: #00adee !important;
	  display: inline-block;
	  font-size: 18px;
	}
	.mobileMenu a.suBtn {
	  color: #fff;
	}
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="mobile-menu-button menuBtn">Open</span>
  <nav class="mobileMenu">
  <ul>
    <li><a href="index.html">Home</a></li>
    <li><a href="testimonials.html">Testimonials</a></li>
    <li><a href="contact.html">Contact</a></li>
  </ul>
</nav>

$(this).toggleClass('act');

to

$('.menuBtn').toggleClass('act');

because this will return the only span which is clicked not other. Hence it is not going toggle class on both div.

please find working snippet below

$(document).ready(function(){
  $('.menuBtn').on('click touch', function () {
		 $('.menuBtn').toggleClass('act');
			if($(this).hasClass('act')) {
				$('.mobileMenu').addClass('act');
				//$('body').addClass('positionfixed');
			}
			else {
				$('.mobileMenu').removeClass('act');
				//$('body').removeClass('positionfixed');
			}
	});
  	});
.mobile-menu-button{
		display:block;
		position:fixed;
		top:20px;
		left:20px;		
		z-index:99;
    background-color:#19b698;
    padding:5px 10px;
    color:#fff;
    font-family: Open Sans;
    font-weight:bold;
	}
	.mobile-menu-button i{
		font-size:26px;
		background-color:#00adee;
		padding:5px 10px;
		color:#fff;
	}
.mobileMenu {
		background-color: #fff !important;
		position: fixed;
		left: 0;
		top: 0;
		z-index: 100;	  
		height: 100vh;
		width: 100vw;
		display: block;
		text-align: center;
		opacity: 0;
		-webkit-transition: all 500ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
		transition: all 500ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
		-webkit-transform: scale(0);
			  transform: scale(0);
		overflow:hidden;
	}
	.mobileMenu img{
		max-width:90%;
		margin:0 auto;
		margin-top:20px;
		margin-bottom:10px;
		border-bottom:1px dotted #717274;
		padding-bottom:20px;
	}
	.mobileMenu.act {
		opacity: 1;
		-webkit-transform: scale(1);
			  transform: scale(1);
	}
	.mobileMenu.act ul li {
		opacity: 1;
		-webkit-transform: translateX(0);
			  transform: translateX(0);
		display:block !important;
	}
	.mobileMenu ul {
		display: block;
		vertical-align: middle;
	}
	.mobileMenu li {
		padding: 10px 0 !important;
		-webkit-transition: all 400ms 510ms;
		transition: all 400ms 510ms;
		opacity: 0;
	}
	.mobileMenu li:nth-child(odd) {
	  -webkit-transform: translateX(30%);
			  transform: translateX(30%);
	}
	.mobileMenu li:nth-child(even) {
	  -webkit-transform: translateX(-30%);
			  transform: translateX(-30%);
	}
	.mobileMenu li:last-child {
	  -webkit-transform: none;
			  transform: none;
	}
	.mobileMenu a {
	  color: #00adee !important;
	  display: inline-block;
	  font-size: 18px;
	}
	.mobileMenu a.suBtn {
	  color: #fff;
	}
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="mobile-menu-button menuBtn">Open</span>
  <nav class="mobileMenu">
  <span class="mobile-menu-button menuBtn">Close</span>						
  <ul>
    <li><a href="index.html">Home</a></li>
    <li><a href="testimonials.html">Testimonials</a></li>
    <li><a href="contact.html">Contact</a></li>
  </ul>
</nav>

In fact, there are two buttons (1 for open, 1 for close).

The 1 first click on "open" works, but then, it doesn't because the close button does not have the act class.

I think you should toggle class on both :

$('.menuBtn').on('click touch', function () {
		**$('.menuBtn')**.toggleClass('act');
    ...
    }

发布评论

评论列表(0)

  1. 暂无评论