单击外部菜单关闭 jquery

因此,我有一个下拉菜单,可以根据业务需求在单击时显示。鼠标离开菜单后,菜单会再次隐藏起来。

但是现在我被要求在用户点击文档上的任何地方之前保留它。如何才能做到这一点?

这是我现在所拥有的东西的一个简化版本:

$(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()想它会触发任何不是菜单,但它没有工作。

171891 次浏览

Take a look at the approach this question used:

How do I detect a click outside an element?

Attach a click event to the document body which closes the window. Attach a separate click event to the window which stops propagation to the document body.
$('html').click(function() {
//Hide the menus if visible
});


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

2 options that you can investigate:

  • On showing of the menu, place a large empty DIV behind it covering up the rest of the page and give that an on-click event to close the menu (and itself). This is akin to the methods used with lightboxes where clicking on the background closes the lightbox
  • On showing of the menu, attach a one-time click event handler on the body that closes the menu. You use jQuery's '.one()' for this.

If using a plugin is ok in you case, then I suggest Ben Alman's clickoutside plugin located here:

its usage is as simple as this:

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

hope this helps.

I think you need something like this: 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();
}
});
});
});

I hope it useful for you!

The answer is right, but it will add a listener that will be triggered every time a click occurs on your page. To avoid that, you can add the listener for just one time :

$('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: if you want to avoid the stopPropagation() on the initial button you can use this

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

what about this?

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

even i came across the same situation and one of my mentor put this idea across to myself.

step:1 when clicked on the button on which we should show the drop down menu. then add the below class name "more_wrap_background" to the current active page like shown below

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

step-2 then add a clicks for the div tag like

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

where hideDropDown is the function to be called to hide drop down menu

Step-3 and important step while hiding the drop down menu is that remove that class you that added earlier like

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

I am removing by using its id in the above code

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

I found a variant of Grsmto's solution and Dennis' solution fixed my issue.

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

And better to set the listener only when your menu is being visible and always remove the listener after menu becomes hidden.

I find it more useful to use mousedown-event instead of click-event. The click-event doesn't work if the user clicks on other elements on the page with click-events. In combination with jQuery's one() method it looks like this:

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

I use this solution with multiple elements with the same behavior in the same page:

$("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() is a bad idea, this breaks standard behaviour of many things, including buttons and links.

The stopPropagation options are bad because they can interfere with other event handlers including other menus that might have attached close handlers to the HTML element.

Here is a simple solution based on user2989143's answer:

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

Use the ':visible' selector. Where .menuitem is the to-hide element(s) ...

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

Or if you already have the .menuitem element(s) in a var ...

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

I have recently faced the same issue. I wrote the following code:

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

It has worked for me perfectly.

It doesn't have to be complicated.

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

If you are not using jQuery and wanted to do it with pure CSS and HTML this is the solution.

  • Create a trigger element and inside it write your popup element.
  • Attach a click handler to unhide the popup on the click of the trigger element.
  • Have a backdrop element that stretches to the entire screen width and attach click handlers to that which hides the popup.
  • All attached click handlers should stop the event from propagating so other handlers are not called.

Find live code below

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>

Looks through these answers and this is how i ended up doing it

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

});