单击外部菜单以关闭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()想法,认为它会触发菜单上没有的任何东西,但是没有用。



Answers:


196

看一下这个问题使用的方法:

如何检测元素外部的点击?

将单击事件附加到关闭窗口的文档主体。将单独的click事件附加到窗口,以停止传播到文档主体。
$('html').click(function() {
  //Hide the menus if visible
});

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


16
它非常美,但是您应该使用$('html')。click()而不是主体。身体始终具有其内容的高度。它内容不多或屏幕非常高,仅适用于身体填充的部分。复制自:stackoverflow.com/questions/152975/…– meo 2011年2月25日15:35
NickGreen 2012年

很好的解决方案。任何想法为什么它与.click()一起使用而不与.live('click',func ...?一起使用?
2013年

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 2013年

没关系,我没有看到“一个”功能,现在我明白了它为什么起作用:api.jquery.com/one
eselk

2
不错的解决方案,但我不得不e.stopPropagation()在Chrome中使用,以阻止第一个事件在one()处理程序中触发
antfx 2015年

18

这些stopPropagation选项很糟糕,因为它们会干扰其他事件处理程序,包括可能会将关闭处理程序附加到HTML元素的其他菜单。

这是一个基于user2989143的答案的简单解决方案:

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

17

如果您可以使用插件,那么我建议Ben Alman位于此处的clickoutside插件:

它的用法很简单:

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

希望这可以帮助。


8

您可以调查2个选项:

  • 在显示菜单时,在其后面放置一个大的空DIV,以覆盖页面的其余部分,并提供一个单击事件以关闭菜单(及其本身)。这类似于灯箱使用的方法,其中单击背景会关闭灯箱
  • 在显示菜单时,在关闭菜单的主体上附加一个单击事件处理程序。为此,您使用jQuery的'.one()'。

6

我找到了Grsmto解决方案的一种变体,而Dennis的解决方案解决了我的问题。

$(".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
Code Commander

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-event更有用。如果用户点击带有点击事件的页面上的其他元素,则点击事件将不起作用。结合jQuery的one()方法,它看起来像这样:

$("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);

其中hideDropDown是要调用以隐藏下拉菜单的函数

隐藏下拉菜单的第3步和重要步骤是删除您之前添加的类,例如

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

我通过在上面的代码中使用其ID进行删除

.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

使用':visible'选择器。其中.menuitem是要隐藏的元素...

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

或者,如果您已经在变量中包含.menuitem元素,则...

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.