简体   繁体   中英

Click to close jQuery dropdown menu on mobile devices while retaining other behavior

I have a pretty simple jQuery dropdown menu with links in the usual ul/li list arrangement. The code for the dropdown is as follows:

$('body').ready(function() {
      if(screen.width <= 720) {
          $('.dropdown').hover(function() { $(this).find('.subMenu').toggle(); });
          $('.dropdown').click(function() { if( $('this').css('display') != 'none') {
              $('this').toggle();
              }
          });
      }
      else
      {
          $('.dropdown').hover(
              function() { $(this).stop(true,true).find('.subMenu').slideDown("fast"); },
              function() { $(this).stop(true,true).find('.subMenu').hide(); } 
          );
      }
  });

On mobile devices (ignore the 720 width, it's just for testing right now), I would like to achieve the following functionality:

  • User taps link with a dropdown menu > If menu is open, close it

  • User taps link while another menu is already open > Close previous menu, open current menu

  • User taps somewhere else on the page > Close any open menus

I found that the hover function actually handles #2 and #3, but I can't figure out how to get #1 working. I'm fairly certain that I know why this particular attempt

$('.dropdown').click(function() { if( $('this').css('display') != 'none') {
      $('this').toggle();
      }
});

fails. I'm guessing that the click (or tap, in this case) triggers the hover event, which seems to take precedence and therefore displays the menu, instead of hiding it.

How can I get this working on mobile devices?

Edit: I'm using jQuery v1.7.2

HTML list structure is as follows, in case it helps someone (abridged version):

    <div id="navbar">
      <ul>
        <li class="dropdown"><a href="#">Link A</a></li>
        <li class="dropdown"><a href="#">Link B</a>
          <ul class="subMenu">
            <li><a href="#">Link 1</a></li>
            <li><a href="#">Link 2</a></li>
          </ul>
        </li>
      </ul>
    </div>

if( $('this').css('display') != 'none') can be replaced with if($('this').is(':hidden'))

you can use .siblings() to close other menus... cant see html code to tell how exactly selector should look like.

As option you can add some class to check if there is other opened menus...

  $('.dropdown').hover(function() { 
      $('.openedMenu .subMenu').hide().removeClass('openedMenu');
      $(this).find('.subMenu').toggle(); 
      $(this).addClass('openedMenu');
  });
  $('.dropdown').click(function() { 
      if( $('this').is(':hidden')) {
          $('this').toggle();
      }
  });

I have worked in only 1 mobile web project but I had problems with click event too. I was using jQuery mobile framework. The workaround was using 'tap' event, included in jQm instead of click. As I guess you aren't using jQuery mobile, I found this plugin which helps you to create 'tap' events: http://aanandprasad.com/articles/jquery-tappable/

If you use jq 1.7+ then try this DEMO HERE http://jsfiddle.net/SCN5T/3/

$(function(){
    $(document).mousedown(function(){
         $('.dropdown .active').removeClass('active').children('ul').hide();
    })
    $('.dropdown').on('mousedown','.subMenu', function(e){
        e.stopPropagation();
        var elem = $(this);
        if(elem.is('.active')) {
            elem.children('ul').slideUp(150);
            elem.removeClass('active');
        } else {
             $('.dropdown .active').removeClass('active').children('ul').hide();
            elem.addClass('active').children('ul').slideDown(150);
        }
    });
    $('.subMenu').on('mousedown','ul', function(e){
        e.stopPropagation();
        alert('menu item clicked');
    });       
})

The following bit of code did the trick for my particular problem:

$('html').mousedown(function() {
    $('.subMenu').hide();
    });

$('#navbar').mousedown(function(event) {
    event.stopPropagation();
    });

$('.dropdown').mousedown(function() {
    var ele = $(this).find('.subMenu');
    $('#navbar').find('.subMenu').each(function(index) { if(!$(this).is(ele)) $(this).hide(); } );
    ele.toggle();
    });

The basic idea I followed was to find the subMenus when receiving a mousedown event and hide them, unless the element was the menu the user clicked on. The toggle then either shows or hides the menu. The event propagation portion and body/html hide portion are from acrashik's answer and the change to $('html') is from this answer .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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