Клацніть зовнішнє меню, щоб закрити jquery


107

Тож у мене випадаюче меню, яке відображається при натисканні, відповідно до бізнес-вимог. Меню знову стає прихованим після того, як ви відімкнете його мишкою.

Але зараз мене просять, щоб він залишався на місці, поки користувач не клацне де-небудь на документі. Як це можна досягти?

Це спрощена версія того, що я маю зараз:

$(document).ready(function() {
  $("ul.opMenu li").click(function(){
   $('#MainOptSubMenu',this).css('visibility', 'visible');
  });

  $("ul.opMenu li").mouseleave(function(){
      $('#MainOptSubMenu',this).css('visibility', 'hidden');
  });
});



<ul  class="opMenu">
  <li id="footwo" class="">
    <span id="optImg" style="display: inline-block;"> <img src="http://localhost.vmsinfo.com:8002/insight/images/options-hover2.gif"/> </span>
      <ul id="MainOptSubMenu" style="visibility: hidden; top: 25px; border-top: 0px solid rgb(217, 228, 250); background-color: rgb(217, 228, 250); padding-bottom: 15px;">
        <li>some</li>
       <li>nav</li>
       <li>links</li>
       </ul>
    </li>
</ul> 

Я спробував щось подібне, $('document[id!=MainOptSubMenu]').click(function()думаючи, що це спровокує все, що не було меню, але це не спрацювало.



Відповіді:


196

Погляньте на підхід, який використовується в цьому питанні:

Як виявити клацання поза елементом?

Приєднайте подію клацання до органу документа, який закриває вікно. До вікна приєднайте окрему подію клацання, яка зупиняє розповсюдження на тілі документа.
$('html').click(function() {
  //Hide the menus if visible
});

$('#menucontainer').click(function(event){
    event.stopPropagation();
});


16
дуже красиво, але ви повинні використовувати $ ('html'). click (), а не тіло. Тіло завжди має висоту свого вмісту. У ньому немає великого вмісту або екран дуже високий, він працює лише на тій частині, яку заповнює тіло. Копіювати з: stackoverflow.com/questions/152975/… - 25 лютого '11 о 15:35
— NickGreen

чудове рішення. будь-яка ідея, чому це працює з .click (), а не з .live ('натискання', func ...?
— Hat

3
Єдина проблема такого підходу полягає в тому, що об'єкти, які вже мають слухач клацань, які stopPropagation з інших причин не впливають. Я розумію, чому це так, але це все-таки обмеження цього рішення.
— DanH

53

Відповідь правильна, але вона додасть слухача, який буде спрацьовувати кожного разу, коли на вашій сторінці відбувається клацання. Щоб уникнути цього, ви можете додати слухача лише один раз:

$('a#menu-link').on('click', function(e) {
    e.preventDefault();
    e.stopPropagation();

    $('#menu').toggleClass('open');

    $(document).one('click', function closeMenu (e){
        if($('#menu').has(e.target).length === 0){
            $('#menu').removeClass('open');
        } else {
            $(document).one('click', closeMenu);
        }
    });
});

Редагувати: якщо ви хочете уникнути stopPropagation()початкової кнопки, ви можете скористатися цією

var $menu = $('#menu');

$('a#menu-link').on('click', function(e) {
    e.preventDefault();

    if (!$menu.hasClass('active')) {
        $menu.addClass('active');

        $(document).one('click', function closeTooltip(e) {
            if ($menu.has(e.target).length === 0 && $('a#menu-link').has(e.target).length === 0) {
                $menu.removeClass('active');
            } else if ($menu.hasClass('active')) {
                $(document).one('click', closeTooltip);
            }
        });
    } else {
        $menu.removeClass('active');
    }
});

Я дуже бачу такий код, чи не додав би цей документ нову функцію клацання в документ щоразу, коли натискається посилання на меню? Отже, якщо ви клацнете посилання меню 1000 разів, не оновлюючи сторінку, у вас буде 1000 функцій, які займають пам'ять, а також виконуються?
— eselk

Не забудьте, я не бачив функції "один", тепер я розумію, чому це працює: api.jquery.com/one
— eselk

2
приємне рішення, але мені довелося використовувати e.stopPropagation()в Chrome, щоб зупинити першу подію від стрільби в one()обробнику
— antfx

18

The stopPropagation опції погано , тому що вони можуть перешкодити іншим обробникам подій , включаючи інше меню , які , можливо, прикріплені близько обробник до HTML - елементу.

Ось просте рішення , засноване на user2989143 «s відповідь:

$('html').click(function(event) {
    if ($(event.target).closest('#menu-container, #menu-activator').length === 0) {
        $('#menu-container').hide();
    }
});

17

Якщо з використанням плагіна у вашому випадку все нормально, я пропоную плагіну Бен Альмана, який знаходиться тут :

його використання так само просто, як це:

$('#menu').bind('clickoutside', function (event) {
    $(this).hide();
});

сподіваюся, що це допомагає.


8

2 варіанти, які можна дослідити:

  • Показуючи меню, поставте за ним великий порожній DIV, який закриває решту сторінки, і дайте йому подію, що натискається, щоб закрити меню (і себе). Це схоже на методи, що застосовуються у лайтбоксах, коли клацання на тлі закриває лайтбокс
  • Показуючи меню, приєднайте обробник подій одноразового натискання на тілі, яке закриває меню. Ви використовуєте для цього jQuery '.one ()'.

6

Я знайшов варіант вирішення Grsmto в і рішення Денніса зосередив своє питання.

$(".MainNavContainer").click(function (event) {
    //event.preventDefault();  // Might cause problems depending on implementation
    event.stopPropagation();

    $(document).one('click', function (e) {
        if(!$(e.target).is('.MainNavContainer')) {
            // code to hide menus
        }
    });
});

5

Я використовую це рішення з декількома елементами з однаковою поведінкою на одній сторінці:

$("html").click(function(event){
    var otarget = $(event.target);
    if (!otarget.parents('#id_of element').length && otarget.attr('id')!="id_of element" && !otarget.parents('#id_of_activator').length) {
        $('#id_of element').hide();
    }
});

stopPropagation () - погана ідея, це порушує стандартну поведінку багатьох речей, включаючи кнопки та посилання.


Це чудово, але ви можете спростити це як$target.closest('#menu-container, #menu-activator').length === 0
— Командир коду

5

Я нещодавно стикався з тим же питанням. Я написав наступний код:

    $('html').click(function(e) {
      var a = e.target;
      if ($(a).parents('.menu_container').length === 0) {
        $('.ofSubLevelLinks').removeClass('active'); //hide menu item
        $('.menu_container li > img').hide(); //hide dropdown image, if any
     }
    });

Це спрацювало для мене чудово.


4

як що до цього?

    $(this).mouseleave(function(){  
        var thisUI = $(this);
        $('html').click(function(){
                thisUI.hide();
            $('html').unbind('click');
         });
     });

3

Мені здається, корисніше використовувати mousedown-event замість події click-події. Подія кліку не працює, якщо користувач натискає на інші елементи на сторінці за допомогою подій клацання. У поєднанні з методом jQuery (() це виглядає приблизно так:

$("ul.opMenu li").click(function(event){

   //event.stopPropagation(); not required any more
   $('#MainOptSubMenu').show();

   // add one mousedown event to html
   $('html').one('mousedown', function(){
       $('#MainOptSubMenu').hide();
   });
});

// mousedown must not be triggered inside menu
$("ul.opMenu li").bind('mousedown', function(evt){
    evt.stopPropagation();
});

3

навіть я зіткнувся з тією ж ситуацією, і один з мого наставника переклав цю ідею на себе.

крок: 1 при натисканні на кнопку, на якій нам слід показати спадне меню. потім додайте нижче назва класу "more_wrap_background" на поточну активну сторінку, як показано нижче

$('.ui-page-active').append("<div class='more_wrap_background' id='more-wrap-bg'> </div>");

крок-2, потім додайте кліки як тег div

$(document).on('click', '#more-wrap-bg', hideDropDown);

де hidDropDown - це функція, яку потрібно викликати, щоб приховати спадне меню

Крок 3 і важливий крок під час приховування випадаючого меню - це видалення класу, який ви додали раніше

$('#more-wrap-bg').remove();

Я видаляю, використовуючи його ідентифікатор у наведеному вище коді

.more_wrap_background {
  top: 0;
  padding: 0;
  margin: 0;
  background: rgba(0, 0, 0, 0.1);
  position: fixed;
  display: block;
  width: 100% !important;
  z-index: 999;//should be one less than the drop down menu's z-index
  height: 100% !important;
}

2
$("html").click( onOutsideClick );
onOutsideClick = function( e )
{
    var t = $( e.target );
    if ( !(
        t.is("#mymenu" ) ||     //Where #mymenu - is a div container of your menu
        t.parents( "#mymenu" ).length > 0
        )   )
    {
        //TODO: hide your menu
    }
};

І краще встановити слухача лише тоді, коли ваше меню буде видно, і завжди видаліть слухача після того, як меню стане прихованим.


1

Я думаю, вам потрібно щось подібне: http://jsfiddle.net/BeenYoung/BXaqW/3/

$(document).ready(function() {
  $("ul.opMenu li").each(function(){
      $(this).click(function(){
            if($(this).hasClass('opened')==false){          
                $('.opMenu').find('.opened').removeClass('opened').find('ul').slideUp();
                $(this).addClass('opened'); 
                $(this).find("ul").slideDown();
            }else{
                $(this).removeClass('opened'); 
                $(this).find("ul").slideUp();               
            }
      });
  });    
});

Я сподіваюся, що це стане в нагоді для вас!


1

Використовуйте перемикач ": видимий". Де .menuitem - це прихований елемент (и) ...

$('body').click(function(){
  $('.menuitem:visible').hide('fast');
});

Або якщо у вас вже є елементи .menuitem у різному ...

var menitems = $('.menuitem');
$('body').click(function(){
  menuitems.filter(':visible').hide('fast');
});

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.