Nhấp vào menu bên ngoài để đóng trong jquery


107

Vì vậy, tôi có một menu thả xuống hiển thị khi nhấp chuột, theo yêu cầu kinh doanh. Menu lại bị ẩn sau khi bạn di chuột ra khỏi nó.

Nhưng bây giờ tôi đang được yêu cầu giữ nguyên vị trí cho đến khi người dùng nhấp vào bất kỳ đâu trên tài liệu. Làm thế nào điều này có thể được thực hiện?

Đây là phiên bản đơn giản của những gì tôi có bây giờ:

$(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> 

Tôi đã thử một cái gì đó như thế này với $('document[id!=MainOptSubMenu]').click(function()suy nghĩ rằng nó sẽ kích hoạt trên bất kỳ thứ gì không phải là menu, nhưng nó không hoạt động.



Câu trả lời:


196

Hãy xem cách tiếp cận mà câu hỏi này đã sử dụng:

Làm cách nào để phát hiện một nhấp chuột bên ngoài một phần tử?

Đính kèm một sự kiện nhấp chuột vào nội dung tài liệu để đóng cửa sổ. Đính kèm sự kiện nhấp chuột riêng biệt vào cửa sổ ngừng truyền vào nội dung tài liệu.
$('html').click(function() {
  //Hide the menus if visible
});

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


16
nó rất đẹp nhưng bạn nên sử dụng $ ('html'). click () không phải nội dung. Cơ thể luôn có chiều cao của nội dung của nó. Nó không có nhiều nội dung hoặc màn hình rất cao, nó chỉ hoạt động trên phần được lấp đầy bởi cơ thể. Sao chép từ: stackoverflow.com/questions/152975/… - meo Ngày 25 tháng 2 '11 lúc 15:35
NickGreen

giải pháp tuyệt vời. bất kỳ ý tưởng nào tại sao nó hoạt động với .click () chứ không phải với .live ('click', func ...?
Hat

3
Vấn đề duy nhất với cách tiếp cận này là các đối tượng đã có trình nghe nhấp chuột mà stopPropagation vì các lý do khác sẽ không có tác dụng. Tôi hiểu tại sao nó lại như vậy, nhưng đó vẫn là một hạn chế của giải pháp này.
DanH

53

Câu trả lời là đúng, nhưng nó sẽ thêm một trình nghe sẽ được kích hoạt mỗi khi nhấp chuột xảy ra trên trang của bạn. Để tránh điều đó, bạn có thể thêm trình nghe chỉ một lần:

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

Chỉnh sửa: nếu bạn muốn tránh stopPropagation()nút ban đầu, bạn có thể sử dụng

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

Tôi thấy mã như thế này rất nhiều, điều này sẽ không thêm chức năng nhấp chuột mới vào tài liệu mỗi khi liên kết menu được nhấp vào? Vì vậy, nếu bạn nhấp vào liên kết menu 1000 lần mà không làm mới trang, bạn sẽ có 1000 chức năng chiếm bộ nhớ và cũng đang thực thi?
eselk

Nevermind, tôi đã không nhìn thấy "một" chức năng, bây giờ tôi hiểu tại sao các công trình này: api.jquery.com/one
eselk

2
giải pháp tốt đẹp nhưng tôi đã phải sử dụng e.stopPropagation()trong Chrome để ngăn chặn sự kiện đầu tiên từ bắn trong one()xử lý
antfx

18

Các stopPropagationtùy chọn không tốt vì chúng có thể gây trở ngại cho các trình xử lý sự kiện khác bao gồm các menu khác có thể đã đính kèm các trình xử lý gần với phần tử HTML.

Đây là một giải pháp đơn giản dựa trên câu trả lời của user2989143 :

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

17

Nếu sử dụng một plugin là ổn trong trường hợp của bạn, thì tôi đề xuất plugin bên ngoài nhấp chuột của Ben Alman nằm ở đây :

cách sử dụng nó đơn giản như sau:

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

hi vọng điêu nay co ich.


8

2 tùy chọn mà bạn có thể điều tra:

  • Khi hiển thị menu, hãy đặt một DIV trống lớn phía sau nó che phần còn lại của trang và tạo sự kiện khi nhấp để đóng menu (và chính nó). Điều này giống với các phương pháp được sử dụng với hộp đèn trong đó nhấp vào nền sẽ đóng hộp đèn
  • Khi hiển thị menu, hãy đính kèm trình xử lý sự kiện nhấp một lần vào phần thân đóng menu. Bạn sử dụng '.one ()' của jQuery cho việc này.

6

Tôi đã tìm thấy một biến thể của giải pháp Grsmtogiải pháp của Dennis đã khắc phục sự cố của tôi.

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

Tôi sử dụng giải pháp này với nhiều phần tử có cùng hành vi trong cùng một trang:

$("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 () là một ý tưởng tồi, điều này phá vỡ hành vi tiêu chuẩn của nhiều thứ, bao gồm cả các nút và liên kết.


Này là rất tốt, nhưng bạn có thể đơn giản hóa nó như$target.closest('#menu-container, #menu-activator').length === 0
Mã Commander

5

Gần đây tôi đã phải đối mặt với cùng một vấn đề. Tôi đã viết mã sau:

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

Nó đã làm việc cho tôi một cách hoàn hảo.


4

cái này thì sao?

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

3

Tôi thấy hữu ích hơn khi sử dụng mousedown-event thay vì click-event. Sự kiện nhấp chuột không hoạt động nếu người dùng nhấp vào các phần tử khác trên trang có sự kiện nhấp chuột. Kết hợp với phương thức one () của jQuery, nó trông giống như sau:

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

thậm chí tôi đã gặp phải tình huống tương tự và một trong những người cố vấn của tôi đã đưa ra ý tưởng này cho chính tôi.

bước: 1 khi nhấp vào nút mà chúng ta sẽ hiển thị menu thả xuống. sau đó thêm tên lớp bên dưới "more_wrap_background" vào trang hoạt động hiện tại như hình dưới đây

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

bước 2 sau đó thêm các nhấp chuột cho thẻ div như

$(document).on('click', '#more-wrap-bg', hideDropDown);

trong đó hideDropDown là hàm được gọi để ẩn menu thả xuống

Bước 3 và bước quan trọng trong khi ẩn menu thả xuống là xóa lớp bạn đã thêm trước đó như

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

Tôi đang xóa bằng cách sử dụng id của nó trong đoạn mã trên

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

Và tốt hơn là chỉ đặt trình nghe khi menu của bạn đang hiển thị và luôn xóa trình nghe sau khi menu bị ẩn.


1

Tôi nghĩ bạn cần một cái gì đó như thế này: 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();               
            }
      });
  });    
});

Tôi hy vọng nó hữu ích cho bạn!


1

Sử dụng bộ chọn ': hiển thị'. Trong đó .menuitem là (các) phần tử cần ẩn ...

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

Hoặc nếu bạn đã có (các) phần tử .menuitem trong var ...

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

0

Nó không cần phải phức tạp.

$(document).on('click', function() {
    $("#menu:not(:hover)").hide();
});
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.