Why jQuery does not match ": not (#menu *)"

I have a homerolled Javascript based navigation bar (I want it to be clicked rather than freezing for mobility). I tried to make HTML, CSS and Javascript as simple as possible.

I put the listener in the body to close the menu bars if you click elsewhere on the website. I am trying to filter the listener so that it does not work if you click on any part of the menu bar. This is to ensure that drop-down lists do not go back when you click on an item in the drop-down list.

I expect the following combining element to ONLY match elements that are descendants of a top-level menu item. Any advice on why this is not working would be greatly appreciated.

EDIT: I understand that you can use an arbitrary function to evaluate the appearance of the bubble and decide if you should act on this, but I'm more interested in why the selector below .on () does not work as I expect.

$("body").on("click", ":not(#menu *)", function (e) { $("#menu a").next().slideUp(DROP_DOWN_TIME); }); 

http://jsfiddle.net/auKzt/16/

HTML

 <body> <div>HEADER</div> <ul id="menu" class="cf"> <li><a href="#">FooafsdasiuhfauhfuahsdfFooaf sdasiuhfauhfuahsdfFooafsdasiuhfauhfuahsdf</a> <ul> <li><a href="#">Subitem asdasdasd 1 sadad</a> </li> <li>Subitem 2</li> <li>Subitem 3</li> </ul> </li> <li><a href="#">Bar</a> <ul> <li>Subitem 1</li> <li>Subitem 2</li> <li>Subitem 3</li> </ul> </li> <li>Qux</li> </ul> <div>CONTENT</div> <div>FOOTER</div> </body> 

JAVASCRIPT

 $(document).ready(function () { var DROP_DOWN_TIME = 200; //Setup hidden dropdowns $("#menu > li > a").next().toggle(); //Hide or unhide dropdowns onclick $("#menu > li > a").click(function (e) { $("#menu a").next().not($(e.target).next()).slideUp(DROP_DOWN_TIME); $(e.target).next().slideToggle(DROP_DOWN_TIME); e.stopPropagation(); }); $("body").on("click", ":not(#menu *)", function (e) { $("#menu a").next().slideUp(DROP_DOWN_TIME); }); }); 

CSS

 #menu { width: 900px; padding: 0; margin: 0; } /* Top level menu container */ #menu li { background-color: aqua; border: 1px solid black; padding: 2px; } /* Top level menu items */ #menu > li { display: inline-block; float: left; position: relative; } /* Submenu container */ #menu > li > ul { position:absolute; padding: 0; margin: 0; top: 100%; left: -1px; } /* Submenu Items */ #menu > li > ul > li { display: block; float: none; white-space: nowrap; } .cf:before, .cf:after { content:" "; /* 1 */ display: table; /* 2 */ } .cf:after { clear: both; } 
+4
source share
2 answers

It does not work because the click is in a menu item. The contents inside are caught.

You also need to add a menu item.

 $("body").on("click", ":not(#menu, #menu *)", function (e) { ^^^^^^ 
+3
source

Try this instead

 $("body").on("click", function (e) { if( e.taget.id !== 'menu' && !$(e.target).closest('#menu').length) { $("#menu a").next().slideUp(DROP_DOWN_TIME); } }); 
-1
source

Source: https://habr.com/ru/post/1481816/


All Articles