Klik menu luar untuk menutup jquery

107

Jadi saya memiliki menu drop-down yang ditampilkan dengan sekali klik, sesuai kebutuhan bisnis. Menu menjadi tersembunyi lagi setelah Anda mengarahkan mouse menjauh darinya.

Tapi sekarang saya diminta untuk membuatnya tetap di tempatnya sampai pengguna mengklik di mana saja pada dokumen. Bagaimana ini bisa dicapai?

Ini adalah versi sederhana dari apa yang saya miliki sekarang:

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

Saya mencoba sesuatu seperti ini dan $('document[id!=MainOptSubMenu]').click(function()berpikir itu akan memicu apa pun yang bukan menu, tetapi tidak berhasil.

George
sumber

Jawaban:

196

Lihatlah pendekatan yang digunakan pertanyaan ini:

Bagaimana cara mendeteksi klik di luar elemen?

Lampirkan acara klik ke badan dokumen yang menutup jendela. Lampirkan acara klik terpisah ke jendela yang menghentikan penyebaran ke badan dokumen.
$('html').click(function() {
  //Hide the menus if visible
});

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

Jon W.
sumber
16
ini sangat indah tetapi Anda harus menggunakan $ ('html']. click () bukan body. Tubuh selalu memiliki ketinggian isinya. Isinya tidak banyak atau layarnya sangat tinggi, hanya berfungsi pada bagian yang diisi oleh bodi. Salin dari: stackoverflow.com/questions/152975/… - meo 25 Feb '11 pukul 15:35
NickGreen
solusi yang bagus. tahu mengapa ini bekerja dengan .click () dan bukan dengan .live ('click', func ...?
Hat
3
Satu-satunya masalah dengan pendekatan ini adalah bahwa objek yang sudah memiliki listener klik yang stopPropagation karena alasan lain tidak berpengaruh. Saya mengerti mengapa demikian, tetapi masih ada batasan dari solusi ini.
DanH
53

Jawabannya benar, tetapi itu akan menambahkan pendengar yang akan dipicu setiap kali klik terjadi di halaman Anda. Untuk menghindarinya, Anda hanya dapat menambahkan listener satu kali:

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

Edit: jika Anda ingin menghindari stopPropagation()tombol awal, Anda dapat menggunakan ini

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');
    }
});
adriendenat
sumber
Saya sering melihat kode seperti ini, bukankah ini akan menambahkan fungsi klik baru ke dokumen setiap kali link menu diklik? Jadi, jika Anda mengklik tautan menu 1000 kali tanpa menyegarkan halaman, Anda akan memiliki 1000 fungsi yang menghabiskan memori dan juga menjalankan?
eselk
Tidak masalah, saya tidak melihat fungsi "satu", sekarang saya mengerti mengapa ini berfungsi: api.jquery.com/one
eselk
2
solusi yang bagus tetapi saya harus menggunakan e.stopPropagation()di Chrome untuk menghentikan peristiwa pertama dari penembakan di one()penangan
antfx
18

The stopPropagationpilihan yang buruk karena mereka dapat mengganggu penangan event lainnya termasuk menu lain yang mungkin telah terpasang penangan dekat dengan elemen HTML.

Berikut adalah solusi sederhana berdasarkan user2989143 's jawabannya:

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

Jika menggunakan plugin tidak masalah bagi Anda, maka saya sarankan plugin sisi klik keluar Ben Alman yang terletak di sini :

penggunaannya sesederhana ini:

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

semoga ini membantu.

Hash Subliminal
sumber
8

2 opsi yang dapat Anda selidiki:

  • Saat menampilkan menu, tempatkan DIV kosong yang besar di belakangnya yang menutupi sisa halaman dan berikan event saat diklik untuk menutup menu (dan dirinya sendiri). Ini mirip dengan metode yang digunakan dengan lightbox di mana mengklik latar belakang akan menutup lightbox
  • Saat menampilkan menu, lampirkan pengendali kejadian klik satu kali di badan yang menutup menu. Anda menggunakan '.one ()' jQuery untuk ini.
DA.
sumber
6

Saya menemukan varian solusi Grsmto dan solusi Dennis memperbaiki masalah saya.

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

Saya menggunakan solusi ini dengan banyak elemen dengan perilaku yang sama di halaman yang sama:

$("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 () adalah ide yang buruk, ini merusak perilaku standar dari banyak hal, termasuk tombol dan tautan.

pengguna2989143
sumber
Ini bagus, tetapi Anda dapat menyederhanakannya sebagai$target.closest('#menu-container, #menu-activator').length === 0
Code Commander
5

Saya baru-baru ini menghadapi masalah yang sama. Saya menulis kode berikut:

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

Ini telah bekerja untuk saya dengan sempurna.

Namish
sumber
4

bagaimana dengan ini?

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

Saya merasa lebih berguna untuk menggunakan mousedown-event daripada click-event. Peristiwa klik tidak berfungsi jika pengguna mengklik elemen lain di halaman dengan peristiwa klik. Dalam kombinasi dengan metode one () jQuery akan terlihat seperti ini:

$("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();
});
yeeno
sumber
3

bahkan saya menemukan situasi yang sama dan salah satu mentor saya mengungkapkan ide ini kepada diri saya sendiri.

langkah: 1 ketika mengklik tombol di mana kita harus menampilkan menu drop-down. kemudian tambahkan nama kelas di bawah ini "more_wrap_background" ke halaman aktif saat ini seperti yang ditunjukkan di bawah ini

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

langkah-2 lalu tambahkan klik untuk tag div seperti

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

dimana hideDropDown adalah fungsi yang dipanggil untuk menyembunyikan menu drop down

Langkah-3 dan langkah penting sambil menyembunyikan menu drop down adalah menghapus kelas yang Anda tambahkan sebelumnya

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

Saya menghapus dengan menggunakan id-nya pada kode di atas

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

Dan lebih baik mengatur pendengar hanya ketika menu Anda sedang terlihat dan selalu menghapus pendengar setelah menu disembunyikan.

Олег Всильдеревьев
sumber
1

Saya pikir Anda membutuhkan sesuatu seperti ini: 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();               
            }
      });
  });    
});

Semoga bermanfaat bagi Anda!

Sakata Gintoki
sumber
1

Gunakan pemilih ': terlihat'. Di mana .menuitem adalah elemen yang harus disembunyikan ...

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

Atau jika Anda sudah memiliki elemen .menuitem di var ...

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

Tidak harus rumit.

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