Клацніть зовнішнє меню, щоб закрити 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.