【问题标题】:Click outside menu to close in jquery单击外部菜单以在 jquery 中关闭
【发布时间】:2010-05-19 19:08:56
【问题描述】:

所以我有一个下拉菜单,可以根据业务需求在点击时显示。鼠标移开后,菜单再次隐藏。

但现在我被要求让它保持原位,直到用户单击文档上的任意位置。这如何实现?

这是我现在拥有的简化版本:

$(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() 的操作,认为它会触发任何不是菜单的东西,但它不起作用。

【问题讨论】:

标签: jquery


【解决方案1】:

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

How do I detect a click outside an element?

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

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

【讨论】:

  • 它非常漂亮,但您应该使用 $('html').click() 而不是正文。正文始终具有其内容的高度。内容不多或者屏幕很高的情况下,只对body填充的部分起作用。复制自:stackoverflow.com/questions/152975/… – meo 2011 年 2 月 25 日 15:35
  • 很好的解决方案。知道为什么它适用于 .click() 而不是 .live('click', func...?
  • 这种方法的唯一问题是已经有一个点击监听器的对象由于其他原因而停止传播没有效果。我明白为什么会这样,但它仍然是这个解决方案的一个限制。
【解决方案2】:

答案是正确的,但它会添加一个监听器,每次在您的页面上发生点击时都会触发该监听器。为避免这种情况,您可以只添加一次监听器:

$('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 个函数占用内存并同时执行?
  • 没关系,我没有看到 "one" 功能,现在我明白为什么会这样了:api.jquery.com/one
  • 不错的解决方案,但我不得不在 Chrome 中使用 e.stopPropagation() 来阻止第一个事件在 one() 处理程序中触发
【解决方案3】:

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

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

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

【讨论】:

    【解决方案4】:

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

    它的用法就这么简单:

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

    希望这会有所帮助。

    【讨论】:

      【解决方案5】:

      您可以调查的 2 个选项:

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

      【讨论】:

        【解决方案6】:

        我发现Grsmto's solutionDennis' solution 的变体解决了我的问题。

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

        【讨论】:

          【解决方案7】:

          这个呢?

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

          【讨论】:

            【解决方案8】:

            我将此解决方案与同一页面中具有相同行为的多个元素一起使用:

            $("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
            【解决方案9】:

            我最近遇到了同样的问题。我写了以下代码:

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

            它对我来说非常有效。

            【讨论】:

              【解决方案10】:

              我发现使用 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();
              });
              

              【讨论】:

                【解决方案11】:

                即使我遇到了同样的情况,我的一位导师也将这个想法告诉了我自己。

                step:1 当点击我们应该显示下拉菜单的按钮时。然后将下面的类名“more_wrap_background”添加到当前活动页面,如下所示

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

                step-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;
                }
                

                【讨论】:

                  【解决方案12】:
                  $("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
                      }
                  };
                  

                  最好仅在菜单可见时设置监听器,并在菜单隐藏后始终移除监听器。

                  【讨论】:

                    【解决方案13】:

                    不必复杂。

                    $(document).on('click', function() {
                        $("#menu:not(:hover)").hide();
                    });
                    

                    【讨论】:

                      【解决方案14】:

                      我认为你需要这样的东西: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();               
                                  }
                            });
                        });    
                      });
                      

                      希望对你有用!

                      【讨论】:

                        【解决方案15】:

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

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

                        或者,如果您已经在 var 中拥有 .menuitem 元素...

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

                        【讨论】:

                          【解决方案16】:

                          如果您不使用 jQuery 并希望使用纯 CSS 和 HTML 来实现,这就是解决方案。

                          • 创建一个触发器元素并在其中写入您的弹出元素。
                          • 附加一个单击处理程序以取消隐藏单击触发元素时的弹出窗口。
                          • 拥有一个延伸到整个屏幕宽度的背景元素,并将点击处理程序附加到隐藏弹出窗口的元素。
                          • 所有附加的点击处理程序都应阻止事件传播,以免调用其他处理程序。

                          在下方查找实时代码

                          function showPopup(bShow,args){
                            var popupContainer = document.getElementsByClassName('popup-container')[0];
                            debugger;
                            if(!bShow){
                              popupContainer.classList.add('hide-element')
                            }else{
                              popupContainer.classList.remove('hide-element')
                            }
                            args[0].stopPropagation();
                          }
                          .popup-trigger{
                            cursor: pointer;
                            margin: 10px;
                            padding: 5px;
                            width: fit-content;
                            background: red;
                            border-radius: 5px;
                            position: relative;
                          }
                          
                          .body{
                            width: 100%;
                            height: 1000px;
                            background: yellow;
                            padding: 10px;
                          }
                          
                          .backdrop{
                            width: 100vw;
                            height: 100vh;
                            position: fixed;
                            top: 0;
                            bottom: 0;
                            left: 0;
                            right: 0;
                          }
                          
                          .actual-popup{
                          }
                          .popup-container{
                           top: 30px;
                           width: 100px;
                           height: 50px;
                           background: grey;
                           display: flex;
                           justify-content: center;
                           align-items: center;
                           position: absolute;
                          }
                          
                          .hide-element{
                            visibility: hidden;
                          }
                          <div class="body">
                          
                            <div onclick="showPopup(true,arguments)" class="popup-trigger">Click to open dialog with button
                              <div onclick="showPopup(false,arguments)" class='popup-container hide-element'> 
                               <div onclick="showPopup(false,arguments)" class='backdrop'>  </div>
                               <div onclick="showPopup(true,arguments)" class='actual-popup'> 
                                  <button onclick="showPopup(false,arguments)"> close me </button>
                               </div>
                               
                              </div>
                             
                            </div>
                          </div>

                          【讨论】:

                            【解决方案17】:

                            查看这些答案,这就是我最终这样做的方式

                            $('html').click(function(event) {
                            
                            let openMenuButton = $("#menu-open");
                            let menu = $("#menu-popup");
                            let both = $('#menu-popup, #menu-open');
                            
                                if ( $(event.target).closest(both).length === 0 ) {  
                                    $(menu).hide();
                                    console.log("if statement");
                                    
                                } else if ( $(menu).is(":visible") && $(event.target).closest(openMenuButton).length === 1 ){
                                $(menu).hide();
                                console.log("if ELSE statement");
                                } else {
                                $(menu).show();
                                console.log("ELSE statement");
                                }
                               
                            });

                            【讨论】:

                              猜你喜欢
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 2023-02-23
                              • 2016-04-24
                              • 1970-01-01
                              • 2016-04-18
                              • 1970-01-01
                              相关资源
                              最近更新 更多