メニューの外側をクリックして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/…– meo Feb 25 '11 at 15:35
NickGreen

素晴らしいソリューション。.live( 'click'、func ...?ではなく.click()で動作する理由は何か
ハット

3
このアプローチの唯一の問題は、他の理由でstopPropagationであるクリックリスナーがすでにあるオブジェクトは効果がないことです。なぜそうなのかは理解できますが、それでもこのソリューションの制限事項です。
DanH 2013年

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

気にしないで、私は「one」関数を見なかった、これでなぜこれが機能するのか理解した:api.jquery.com/one
eselk

2
素晴らしい解決策ですがe.stopPropagation()one()ハンドラで最初のイベントが発生しないようにChromeで使用する必要がありました
antfx

18

stopPropagationオプションは、HTML要素にcloseハンドラーをアタッチしている可能性がある他のメニューを含む他のイベントハンドラーに干渉する可能性があるため、不適切です。

これは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をその後ろに配置し、メニュー(およびそれ自体)を閉じるためのクリックイベントを提供します。これは、背景をクリックしてライトボックスを閉じるライトボックスで使用される方法に似ています
  • メニューが表示されたら、メニューを閉じるボディに1回限りのクリックイベントハンドラーをアタッチします。これにはjQueryの '.one()'を使用します。


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

クリックイベントの代わりにマウスダウンイベントを使用する方が便利だと思います。ユーザーがクリックイベントを含むページの他の要素をクリックした場合、クリックイベントは機能しません。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人がこの考えを自分自身に伝えました。

step: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');
});

または、varに.menuitem要素がすでにある場合...

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.