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 ()을 사용해야합니다. 본문에는 항상 내용의 높이가 있습니다. 내용이 많지 않거나 화면이 매우 높고 몸이 가득 찬 부분에서만 작동합니다. 복사
출처

훌륭한 솔루션. .live ( 'click', func가 아닌 .click ()과 함께 작동하는 이유를 아십니까?
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 2013

신경 쓰지 마세요. "one"기능을 보지 못했습니다. 이제 이것이 작동하는 이유를 이해합니다. api.jquery.com/one
eselk 2013

2
좋은 해결책이지만 e.stopPropagation()Chrome에서 첫 번째 이벤트가 one()핸들러 에서 발생하는 것을 막아야했습니다
antfx

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

조사 할 수있는 두 가지 옵션 :

  • 메뉴를 표시 할 때 페이지의 나머지 부분을 덮는 큰 빈 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
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

click-event 대신 mousedown-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');
});

또는 이미 var에 .menuitem 요소가있는 경우 ...

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

0

복잡 할 필요는 없습니다.

$(document).on('click', function() {
    $("#menu:not(:hover)").hide();
});
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.