How do I detect a click outside an element?
我有一些HTML菜单,当用户单击这些菜单的头部时,我会完全显示这些菜单。我想在用户单击菜单区域之外时隐藏这些元素。
jquery是否可以这样做?
1 2 3 | $("#menuscontainer").clickOutsideThisElement(function() { // Hide the menus }); |
NOTE: Using
stopEventPropagation() is something that should be avoided as it breaks normal event flow in the DOM. See this article for more information. Consider using this method instead
将单击事件附加到关闭窗口的文档正文。将一个单独的单击事件附加到容器,该容器将停止向文档正文传播。
1 2 3 4 5 6 7 | $(window).click(function() { //Hide the menus if visible }); $('#menucontainer').click(function(event){ event.stopPropagation(); }); |
您可以监听
如果不是,则单击的元素在
1 2 3 4 5 6 7 | $(document).click(function(event) { $target = $(event.target); if(!$target.closest('#menucontainer').length && $('#menucontainer').is(":visible")) { $('#menucontainer').hide(); } }); |
编辑:2017-06-23
如果计划关闭菜单并希望停止侦听事件,也可以在事件侦听器之后进行清理。此函数将只清理新创建的侦听器,保留
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | export function hideOnClickOutside(selector) { const outsideClickListener = (event) => { $target = $(event.target); if (!$target.closest(selector).length && $(selector).is(':visible')) { $(selector).hide(); removeClickListener(); } } const removeClickListener = () => { document.removeEventListener('click', outsideClickListener) } document.addEventListener('click', outsideClickListener) } |
编辑:2018-03-11
对于那些不想使用jquery的用户。上面的代码是普通的vanillajs(ecmascript6)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | function hideOnClickOutside(element) { const outsideClickListener = event => { if (!element.contains(event.target) && isVisible(element)) { // or use: event.target.closest(selector) === null element.style.display = 'none' removeClickListener() } } const removeClickListener = () => { document.removeEventListener('click', outsideClickListener) } document.addEventListener('click', outsideClickListener) } const isVisible = elem => !!elem && !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ) // source (2018-03-11): https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js |
注:这是基于alex comment,只使用
但是现在所有主要的浏览器都可以使用
How to detect a click outside an element?
原因,这个问题是如此的流行,有这么多的答案是,它是deceptively复杂。八年后,几乎和dozens奇怪的答案,我是真正的看到如何护理已被给定的accessibility大小。
I would like to hide these elements when the user clicks outside the menus' area.
这是一个崇高的事业,是实际的问题。标题的问题与答案的表示,这是他最大的attempt出现大的地址与您的安全unfortunate包含Red Herring。
hint的话:这是"点击"!
你不真的想要handlers bind点击。 如果你是大的dialog handlers结合点击关闭,你已经已经失败。你已经失败的原因是,并非每个triggers
所以让我们rephrase这个问题。
How does one close a dialog when a user is finished with it?
这是目标。不幸的是,现在我们需要的
所以,我们如何可以detect用户使用一个dialog已完成?
一个很好的开始,如果焦点是确定的dialog已经离开了。
小心:是
jquery
1 2 | element.addEventListener('blur', ..., true); // use capture: ^^^^ |
同时,对于许多对话框允许你会需要大的容器获得焦点。添加到允许的dialog
1 2 3 4 5 6 7 | $('a').on('click', function () { $(this.hash).toggleClass('active').focus(); }); $('div').on('focusout', function () { $(this).removeClass('active'); }); |
1 2 3 4 5 6 | div { display: none; } .active { display: block; } |
1 2 3 4 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"> Example Lorem ipsum dolor sit amet. |
如果你的游戏与演示为超过一分钟,你应该很快开始看到的问题。
第一个是,该链接在dialog不是clickable。在试图点击它或它会导致大的标签的dialog closing之前的相互作用需要的地方。这是因为一个关于元素的内在triggers
是queue修复的状态变化对该事件的环。这不能做为
1 2 3 4 5 6 7 8 9 10 | $('.submenu').on({ focusout: function (e) { $(this).data('submenuTimer', setTimeout(function () { $(this).removeClass('submenu--active'); }.bind(this), 0)); }, focusin: function (e) { clearTimeout($(this).data('submenuTimer')); } }); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | $('a').on('click', function () { $(this.hash).toggleClass('active').focus(); }); $('div').on({ focusout: function () { $(this).data('timer', setTimeout(function () { $(this).removeClass('active'); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this).data('timer')); } }); |
1 2 3 4 5 6 | div { display: none; } .active { display: block; } |
1 2 3 4 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"> Example Lorem ipsum dolor sit amet. |
第二期是不会关闭的dialog当的链接是pressed再次。这是因为dialog失去焦点,triggering关闭后的行为,其中的链接点击triggers dialog reopen的大。
类似的前一期的焦点,成为管理国家的需要。给定的状态变化,已经被queued,它只是一个重要的焦点事件的处理:对dialog triggers
<字幕>这个要看<字幕> /熟悉1 2 3 4 5 6 7 8 9 10 | $('a').on({ focusout: function () { $(this.hash).data('timer', setTimeout(function () { $(this.hash).removeClass('active'); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this.hash).data('timer')); } }); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | $('a').on('click', function () { $(this.hash).toggleClass('active').focus(); }); $('div').on({ focusout: function () { $(this).data('timer', setTimeout(function () { $(this).removeClass('active'); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this).data('timer')); } }); $('a').on({ focusout: function () { $(this.hash).data('timer', setTimeout(function () { $(this.hash).removeClass('active'); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this.hash).data('timer')); } }); |
1 2 3 4 5 6 | div { display: none; } .active { display: block; } |
1 2 3 4 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"> Example Lorem ipsum dolor sit amet. |
如果你以为你是做焦点由美国来处理,你可以有更大的自由simplify的用户体验。
这往往是一个"很有"的特征,但它是常见的,当你有一个popup模态或任何你的关键,esc将接近它了。
1 2 3 4 5 6 | keydown: function (e) { if (e.which === 27) { $(this).removeClass('active'); e.preventDefault(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | $('a').on('click', function () { $(this.hash).toggleClass('active').focus(); }); $('div').on({ focusout: function () { $(this).data('timer', setTimeout(function () { $(this).removeClass('active'); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this).data('timer')); }, keydown: function (e) { if (e.which === 27) { $(this).removeClass('active'); e.preventDefault(); } } }); $('a').on({ focusout: function () { $(this.hash).data('timer', setTimeout(function () { $(this.hash).removeClass('active'); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this.hash).data('timer')); } }); |
1 2 3 4 5 6 | div { display: none; } .active { display: block; } |
1 2 3 4 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"> Example Lorem ipsum dolor sit amet. |
如果你知道你有focusable元素内的dialog,你不会需要dialog焦点的直接测量。如果你是,你可以建立一个菜单,菜单的第一项相反的焦点。
1 2 3 4 5 6 7 | click: function (e) { $(this.hash) .toggleClass('submenu--active') .find('a:first') .focus(); e.preventDefault(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | $('.menu__link').on({ click: function (e) { $(this.hash) .toggleClass('submenu--active') .find('a:first') .focus(); e.preventDefault(); }, focusout: function () { $(this.hash).data('submenuTimer', setTimeout(function () { $(this.hash).removeClass('submenu--active'); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this.hash).data('submenuTimer')); } }); $('.submenu').on({ focusout: function () { $(this).data('submenuTimer', setTimeout(function () { $(this).removeClass('submenu--active'); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this).data('submenuTimer')); }, keydown: function (e) { if (e.which === 27) { $(this).removeClass('submenu--active'); e.preventDefault(); } } }); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | .menu { list-style: none; margin: 0; padding: 0; } .menu:after { clear: both; content: ''; display: table; } .menu__item { float: left; position: relative; } .menu__link { background-color: lightblue; color: black; display: block; padding: 0.5em 1em; text-decoration: none; } .menu__link:hover, .menu__link:focus { background-color: black; color: lightblue; } .submenu { border: 1px solid black; display: none; left: 0; list-style: none; margin: 0; padding: 0; position: absolute; top: 100%; } .submenu--active { display: block; } .submenu__item { width: 150px; } .submenu__link { background-color: lightblue; color: black; display: block; padding: 0.5em 1em; text-decoration: none; } .submenu__link:hover, .submenu__link:focus { background-color: black; color: lightblue; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"> <ul class="menu"> <li class="menu__item"> Menu 1 <ul class="submenu" id="menu-1" tabindex="-1"> <li class="submenu__item">Example 1 </li> <li class="submenu__item">Example 2 </li> <li class="submenu__item">Example 3 </li> <li class="submenu__item">Example 4 </li> </ul> </li> <li class="menu__item"> Menu 2 <ul class="submenu" id="menu-2" tabindex="-1"> <li class="submenu__item">Example 1 </li> <li class="submenu__item">Example 2 </li> <li class="submenu__item">Example 3 </li> <li class="submenu__item">Example 4 </li> </ul> </li> </ul> lorem ipsum dolor sit amet. |
这个回答hopefully分布式访问的键盘和鼠的基础支持这一功能,但因为它的已经相当sizable我要讨论任何avoid威-咏叹调的角色和属性,然而,我指的implementers高度recommend将军为细节的角色在什么他们应该使用和其他任何合适的属性。
这里的其他解决方案不适合我,所以我必须使用:
1 2 3 4 | if(!$(event.target).is('#foo')) { // hide menu } |
我有一个应用程序,其工作原理类似于Eran的例子,除了我打开菜单时将Click事件附加到主体上…有点像这样:
1 2 3 4 5 6 7 | $('#menucontainer').click(function(event) { $('html').one('click',function() { // Hide the menus }); event.stopPropagation(); }); |
关于jquery的
1 2 3 4 5 6 | $("#menuscontainer").click(function() { $(this).focus(); }); $("#menuscontainer").blur(function(){ $(this).hide(); }); |
对我来说很好。
现在有了一个插件:外部事件(博客帖子)
当clickoutside处理程序(wlog)绑定到元素时,会发生以下情况:
- 元素被添加到一个数组中,该数组使用clickoutside处理程序保存所有元素。
- (命名空间)单击处理程序绑定到文档(如果尚未绑定)
- 在文档中单击时,将为该数组中不等于click events目标或其父级的元素触发clickoutside事件。
- 此外,clickoutside事件的event.target设置为用户单击的元素(这样您甚至可以知道用户单击了什么,而不仅仅是他单击了外部)。
因此,不会停止任何事件的传播,并且可以将其他单击处理程序与外部处理程序一起"在"元素上方使用。
经过研究,我找到了三个有效的解决方案(我忘记了页面链接以供参考)
第一解1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | //The good thing about this solution is it doesn't stop event propagation. var clickFlag = 0; $('body').on('click', function () { if(clickFlag == 0) { console.log('hide element here'); /* Hide element here */ } else { clickFlag=0; } }); $('body').on('click','#testDiv', function (event) { clickFlag = 1; console.log('showed the element'); /* Show the element */ }); |
二解
1 2 3 4 5 | $('body').on('click', function(e) { if($(e.target).closest('#testDiv').length == 0) { /* Hide dropdown here */ } }); |
第三解
1 2 3 4 5 6 7 8 9 10 | var specifiedElement = document.getElementById('testDiv'); document.addEventListener('click', function(event) { var isClickInside = specifiedElement.contains(event.target); if (isClickInside) { console.log('You clicked inside') } else { console.log('You clicked outside') } }); |
这对我很管用!!
1 2 3 4 5 6 7 | $('html').click(function (e) { if (e.target.id == 'YOUR-DIV-ID') { //do something } else { //do something } }); |
我不认为你真正需要的是当用户单击外部时关闭菜单;你需要的是当用户单击页面上的任何位置时关闭菜单。如果你点击菜单,或者从菜单中点击,它应该右键关闭?
在上面没有找到满意的答案,这促使我前几天写了这篇博文。对于更学究的人来说,有很多问题需要注意:
正如另一张海报所说,gotchas有很多,特别是当你显示的元素(在本例中是菜单)有交互元素时。我发现以下方法相当可靠:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | $('#menuscontainer').click(function(event) { //your code that shows the menus fully //now set up an event listener so that clicking anywhere outside will close the menu $('html').click(function(event) { //check up the tree of the click target to check whether user has clicked outside of menu if ($(event.target).parents('#menuscontainer').length==0) { // your code to hide menu //this event listener has done its job so we can unbind it. $(this).unbind(event); } }) }); |
针对这种情况的一个简单解决方案是:
1 2 3 4 5 6 7 8 9 10 | $(document).mouseup(function (e) { var container = $("YOUR SELECTOR"); // Give you class or ID if (!container.is(e.target) && // If the target of the click is not the desired div or section container.has(e.target).length === 0) // ... nor a descendant-child of the container { container.hide(); } }); |
如果触发了
有关详细信息,请参阅以下日志:http://www.codecanal.com/detect-click-outside-div-using-javascript/
解决方案1
不要使用可能有一些副作用的event.stoppropagation(),只需定义一个简单的标志变量并添加一个
1 2 3 4 5 6 7 8 9 10 11 12 13 | var flag ="1"; $('#menucontainer').click(function(event){ flag ="0"; // flag 0 means click happened in the area where we should not do any action }); $('html').click(function() { if(flag !="0"){ // Hide the menus if visible } else { flag ="1"; } }); |
解决方案2
只有一个简单的
1 2 3 4 5 6 7 8 | $(document).on('click', function(event){ var container = $("#menucontainer"); if (!container.is(event.target) && // If the target of the click isn't the container... container.has(event.target).length === 0) // ... nor a descendant of the container { // Do whatever you want to do when click is outside the element } }); |
检查window click事件目标(它应该传播到窗口,只要它没有被捕获到任何其他地方),并确保它不是任何菜单元素。如果不是,那你就不在菜单上了。
或者检查单击的位置,看看它是否包含在菜单区域中。
我在这样的事情上取得了成功:
1 2 3 4 5 6 7 8 9 10 11 12 13 | var $menuscontainer = ...; $('#trigger').click(function() { $menuscontainer.show(); $('body').click(function(event) { var $target = $(event.target); if ($target.parents('#menuscontainer').length == 0) { $menuscontainer.hide(); } }); }); |
逻辑是:当显示
作为一个变种:
1 2 3 4 5 6 7 8 | var $menu = $('#menucontainer'); $(document).on('click', function (e) { // If element is opened and click target is outside it, hide it if ($menu.is(':visible') && !$menu.is(e.target) && !$menu.has(e.target).length) { $menu.hide(); } }); |
停止事件传播没有问题,并且更好地支持同一页面上的多个菜单,在第一个菜单打开时单击第二个菜单将使第一个菜单在Stoppropagation解决方案中保持打开状态。
我在一些jquery日历插件中找到了这个方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | function ClickOutsideCheck(e) { var el = e.target; var popup = $('.popup:visible')[0]; if (popup==undefined) return true; while (true){ if (el == popup ) { return true; } else if (el == document) { $(".popup").hide(); return false; } else { el = $(el).parent()[0]; } } }; $(document).bind('mousedown.popup', ClickOutsideCheck); |
该事件有一个名为event.path的元素属性,它是"按树顺序排列的所有祖先的静态顺序列表"。要检查事件是来自特定的dom元素还是其子元素,只需检查该特定dom元素的路径。它还可以用于通过逻辑上的
1 2 3 4 5 6 7 8 9 10 11 | $("body").click(function() { target = document.getElementById("main"); flag = event.path.some(function(el, i, arr) { return (el == target) }) if (flag) { console.log("Inside") } else { console.log("Outside") } }); |
1 2 3 | #main { display: inline-block; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"> <ul> <li> Test-Main </li> <li> Test-Main </li> <li> Test-Main </li> <li> Test-Main </li> <li> Test-Main </li> </ul> Outside Main |
所以对你来说应该是
1 2 3 4 5 6 7 8 9 | $("body").click(function() { target = $("#menuscontainer")[0]; flag = event.path.some(function(el, i, arr) { return (el == target) }); if (!flag) { // Hide the menus } }); |
下面是面向未来观众的普通JavaScript解决方案。
单击文档中的任何元素时,如果已切换所单击元素的ID,或者隐藏元素未隐藏且隐藏元素不包含所单击元素,则切换该元素。
1 2 3 4 5 6 7 | (function () { "use strict"; var hidden = document.getElementById('hidden'); document.addEventListener('click', function (e) { if (e.target.id == 'toggle' || (hidden.style.display != 'none' && !hidden.contains(e.target))) hidden.style.display = hidden.style.display == 'none' ? 'block' : 'none'; }, false); })(); |
1 2 3 4 5 6 7 | (function () { "use strict"; var hidden = document.getElementById('hidden'); document.addEventListener('click', function (e) { if (e.target.id == 'toggle' || (hidden.style.display != 'none' && !hidden.contains(e.target))) hidden.style.display = hidden.style.display == 'none' ? 'block' : 'none'; }, false); })(); |
1 2 | Toggle Hidden Div This content is normally hidden. click anywhere other than this content to make me disappear |
如果要在同一页上进行多个切换,可以使用如下方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | (function () { "use strict"; var hiddenItems = document.getElementsByClassName('hidden'), hidden; document.addEventListener('click', function (e) { for (var i = 0; hidden = hiddenItems[i]; i++) { if (!hidden.contains(e.target) && hidden.style.display != 'none') hidden.style.display = 'none'; } if (e.target.getAttribute('data-toggle')) { var toggle = document.querySelector(e.target.getAttribute('data-toggle')); toggle.style.display = toggle.style.display == 'none' ? 'block' : 'none'; } }, false); })(); |
1 2 3 4 5 6 | Toggle Hidden Div This content is normally hidden Toggle Hidden Div This content is normally hidden Toggle Hidden Div This content is normally hidden |
如果您正在为IE和FF 3*编写脚本,并且您只想知道单击是否发生在某个框区域内,您还可以使用如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | this.outsideElementClick = function(objEvent, objElement){ var objCurrentElement = objEvent.target || objEvent.srcElement; var blnInsideX = false; var blnInsideY = false; if (objCurrentElement.getBoundingClientRect().left >= objElement.getBoundingClientRect().left && objCurrentElement.getBoundingClientRect().right <= objElement.getBoundingClientRect().right) blnInsideX = true; if (objCurrentElement.getBoundingClientRect().top >= objElement.getBoundingClientRect().top && objCurrentElement.getBoundingClientRect().bottom <= objElement.getBoundingClientRect().bottom) blnInsideY = true; if (blnInsideX && blnInsideY) return false; else return true;} |
相反,使用流中断、模糊/聚焦事件或任何其他棘手的技术,只需将事件流与元素的亲属关系匹配:
1 2 3 4 5 6 7 8 | $(document).on("click.menu-outside", function(event){ // Test if target and it's parent aren't #menuscontainer // That means the click event occur on other branch of document tree if(!$(event.target).parents().andSelf().is("#menuscontainer")){ // Click outisde #menuscontainer // Hide the menus (but test if menus aren't already hidden) } }); |
要删除"单击外部事件侦听器",只需:
1 | $(document).off("click.menu-outside"); |
我很惊讶没有人真正承认
1 2 3 4 5 6 7 | var button = document.getElementById('button'); button.addEventListener('click', function(e){ e.target.style.backgroundColor = 'green'; }); button.addEventListener('focusout', function(e){ e.target.style.backgroundColor = ''; }); |
1 2 3 4 5 6 7 8 9 | <!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <button id="button">Click</button> </body> </html> |
用途:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | var go = false; $(document).click(function(){ if(go){ $('#divID').hide(); go = false; } }) $("#divID").mouseover(function(){ go = false; }); $("#divID").mouseout(function (){ go = true; }); $("btnID").click( function(){ if($("#divID:visible").length==1) $("#divID").hide(); // Toggle $("#divID").show(); }); |
在文档上挂接一个单击事件侦听器。在事件监听器中,您可以查看事件对象,尤其是event.target,以查看单击了什么元素:
1 2 3 4 5 6 7 | $(document).click(function(e){ if ($(e.target).closest("#menuscontainer").length == 0) { // .closest can help you determine if the element // or one of its ancestors is #menuscontainer console.log("hide"); } }); |
支持最流行的答案,但添加
1 | && (e.target != $('html').get(0)) // ignore the scrollbar |
所以,点击滚动条并不会[隐藏或任何其他]你的目标元素。
我在YUI 3中这样做:
1 2 3 4 5 6 | // Detect the click anywhere other than the overlay element to close it. Y.one(document).on('click', function (e) { if (e.target.ancestor('#overlay') === null && e.target.get('id') != 'show' && overlay.get('visible') == true) { overlay.hide(); } }); |
我正在检查祖先是否不是widget元素容器,
如果目标不是打开小部件/元素的对象,
如果要关闭的小部件/元素已经打开(不那么重要)。
1 2 3 4 5 6 | $(document).click(function() { $(".overlay-window").hide(); }); $(".overlay-window").click(function() { return false; }); |
如果单击文档,则隐藏给定元素,除非单击同一元素。
为了更容易使用和更具表现力的代码,我为此创建了一个jquery插件:
1 2 3 | $('div.my-element').clickOut(function(target) { //do something here... }); |
注意:目标是用户实际单击的元素。但是回调仍然在原始元素的上下文中执行,所以您可以像在jquery回调中预期的那样使用它。
插件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | $.fn.clickOut = function (parent, fn) { var context = this; fn = (typeof parent === 'function') ? parent : fn; parent = (parent instanceof jQuery) ? parent : $(document); context.each(function () { var that = this; parent.on('click', function (e) { var clicked = $(e.target); if (!clicked.is(that) && !clicked.parents().is(that)) { if (typeof fn === 'function') { fn.call(that, clicked); } } }); }); return context; }; |
默认情况下,单击事件侦听器放置在文档上。但是,如果要限制事件侦听器的作用域,可以传入一个jquery对象,该对象表示一个父级元素,该元素将是将要侦听单击的父级元素。这可以防止不必要的文档级事件侦听器。显然,除非提供的父元素是初始元素的父元素,否则它将不起作用。
使用如下:
1 2 3 | $('div.my-element').clickOut($('div.my-parent'), function(target) { //do something here... }); |
功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | $(function() { $.fn.click_inout = function(clickin_handler, clickout_handler) { var item = this; var is_me = false; item.click(function(event) { clickin_handler(event); is_me = true; }); $(document).click(function(event) { if (is_me) { is_me = false; } else { clickout_handler(event); } }); return this; } }); |
用途:
1 2 3 4 5 6 | this.input = $('<input>') .click_inout( function(event) { me.ShowTree(event); }, function() { me.Hide(); } ) .appendTo(this.node); |
功能非常简单:
1 2 3 4 5 6 | ShowTree: function(event) { this.data_span.show(); } Hide: function() { this.data_span.hide(); } |
我最后做了这样的事情:
1 2 3 4 5 6 7 | $(document).on('click', 'body, #msg_count_results .close',function() { $(document).find('#msg_count_results').remove(); }); $(document).on('click','#msg_count_results',function(e) { e.preventDefault(); return false; }); |
我在新容器中有一个关闭按钮,用于最终用户友好的用户界面。为了不通过,我不得不用返回错误。当然,有一个a href在那里带你去某个地方会很好,或者你可以改为调用一些ajax的东西。不管怎样,对我来说都可以。正是我想要的。
我们实现了一个解决方案,部分基于上面一个用户的评论,这对我们非常有效。当单击这些元素时,我们使用它来隐藏搜索框/结果,不包括最初的元素。
1 2 3 4 5 6 7 8 | // HIDE SEARCH BOX IF CLICKING OUTSIDE $(document).click(function(event){ // IF NOT CLICKING THE SEARCH BOX OR ITS CONTENTS OR SEARCH ICON if ($("#search-holder").is(":visible") && !$(event.target).is("#search-holder *, #search")) { $("#search-holder").fadeOut('fast'); $("#search").removeClass('active'); } }); |
它首先检查搜索框是否也可见,在我们的例子中,它还删除了隐藏/显示搜索按钮上的活动类。
这应该有效:
1 2 3 4 5 6 7 | $('body').click(function (event) { var obj = $(event.target); obj = obj['context']; // context : clicked element inside body if ($(obj).attr('id') !="menuscontainer" && $('#menuscontainer').is(':visible') == true) { //hide menu } }); |
这是我解决这个问题的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | $(document).ready(function() { $('#user-toggle').click(function(e) { $('#user-nav').toggle(); e.stopPropagation(); }); $('body').click(function() { $('#user-nav').hide(); }); $('#user-nav').click(function(e){ e.stopPropagation(); }); }); |
如果有人对这里的JavaScript解决方案(ES6)感兴趣:
1 2 3 4 5 6 | window.addEventListener('mouseup', e => { if (e.target != yourDiv && e.target.parentNode != yourDiv) { yourDiv.classList.remove('show-menu'); //or yourDiv.style.display = 'none'; } }) |
和ES5,以防万一:
1 2 3 4 5 | window.addEventListener('mouseup', function (e) { if (e.target != yourDiv && e.target.parentNode != yourDiv) { yourDiv.classList.remove('show-menu'); //or yourDiv.style.display = 'none'; } |
(});
我使用了下面的脚本并完成了jquery。
1 2 3 4 5 6 | jQuery(document).click(function(e) { var target = e.target; //target div recorded if (!jQuery(target).is('#tobehide') ) { jQuery(this).fadeOut(); //if the click element is not the above id will hide } }) |
在下面查找HTML代码
1 2 | Hello I am the title I will hide when you click outside of me |
你可以在这里阅读教程
下面是我要解决的问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | $(window).click(function (event) { //To improve performance add a checklike //if(myElement.isClosed) return; var isClickedElementChildOfMyBox = isChildOfElement(event,'#id-of-my-element'); if (isClickedElementChildOfMyBox) return; //your code to hide the element }); var isChildOfElement = function (event, selector) { if (event.originalEvent.path) { return event.originalEvent.path[0].closest(selector) !== null; } return event.originalEvent.originalTarget.closest(selector) !== null; } |
当只管理一个元素时,这里的解决方案可以很好地工作。然而,如果有多个元素,问题就复杂得多。使用e.stoppropagation()和所有其他方法的技巧将不起作用。
我想出了一个解决办法,也许不是那么容易,但总比什么都没有好。看一看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | $view.on("click", function(e) { if(model.isActivated()) return; var watchUnclick = function() { rootView.one("mouseleave", function() { $(document).one("click", function() { model.deactivate(); }); rootView.one("mouseenter", function() { watchUnclick(); }); }); }; watchUnclick(); model.activate(); }); |
这里是一个简单的纯javascript解决方案。它是最新的ES6:
1 2 3 4 5 6 7 8 9 10 11 12 | var isMenuClick = false; var menu = document.getElementById('menuscontainer'); document.addEventListener('click',()=>{ if(!isMenuClick){ //Hide the menu here } //Reset isMenuClick isMenuClick = false; }) menu.addEventListener('click',()=>{ isMenuClick = true; }) |
老实说,我不喜欢以前的任何解决方案。
最好的方法是将"单击"事件绑定到文档,并比较该单击是否确实在元素之外(就像Art在他的建议中所说)。
但是,您会遇到一些问题:您将永远无法解除绑定,并且您不能有一个外部按钮来打开/关闭该元素。
这就是为什么我写了这个小插件(点击这里链接),以简化这些任务。能简单点吗?
1 2 3 4 5 6 7 8 9 10 11 12 13 | Toggle the menu<br/> I should be toggled when the above menu is clicked, and hidden when user clicks outside. $('#theButton').click(function(){ $('#theMenu').slideDown(); }); $("#theMenu").dClickOutside({ ignoreList: $("#theButton") }, function(clickedObj){ $(this).slideUp(); }); |
我只想让@pistos的回答更明显,因为它隐藏在评论中。
这个解决方案对我很有效。普通JS:
1 2 3 4 5 6 | var elementToToggle = $('.some-element'); $(document).click( function(event) { if( $(event.target).closest(elementToToggle).length === 0 ) { elementToToggle.hide(); } }); |
在咖啡中描述:
1 2 3 4 | elementToToggle = $('.some-element') $(document).click (event) -> if $(event.target).closest(elementToToggle).length == 0 elementToToggle.hide() |
这对我来说非常及时:
1 2 3 | $('body').click(function() { // Hide the menus if visible. }); |
这里还有一个解决方案:
http://jsfiddle.net/zr76d/
用途:
1 2 | Open / Close Menu I am a menu, whoa is me. |
插件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | (function($) { var clickOutsideElements = []; var clickListener = false; $.fn.clickOutside = function(options, ignoreFirstClick) { var that = this; if (ignoreFirstClick == null) ignoreFirstClick = true; if (options !="disable") { for (var i in clickOutsideElements) { if (clickOutsideElements[i].element[0] == $(this)[0]) return this; } clickOutsideElements.push({ element : this, clickDetected : ignoreFirstClick, fnc : (typeof(options) !="function") ? function() {} : options }); $(this).on("click.clickOutside", function(event) { for (var i in clickOutsideElements) { if (clickOutsideElements[i].element[0] == $(this)[0]) { clickOutsideElements[i].clickDetected = true; } } }); if (!clickListener) { if (options != null && typeof(options) =="function") { $('html').click(function() { for (var i in clickOutsideElements) { if (!clickOutsideElements[i].clickDetected) { clickOutsideElements[i].fnc.call(that); } if (clickOutsideElements[i] != null) clickOutsideElements[i].clickDetected = false; } }); clickListener = true; } } } else { $(this).off("click.clickoutside"); for (var i = 0; i < clickOutsideElements.length; ++i) { if (clickOutsideElements[i].element[0] == $(this)[0]) { clickOutsideElements.splice(i, 1); } } } return this; } })(jQuery); |
最广泛的方法是选择网页上的所有内容,但不希望检测到单击的元素除外,并在打开菜单时绑定单击事件。
然后当菜单关闭时,移除绑定。
使用.stoppropagation防止事件影响menusContainer的任何部分。
1 2 3 4 5 6 7 8 9 10 11 12 | $("*").not($("#menuscontainer")).bind("click.OutsideMenus", function () { // hide the menus //then remove all of the handlers $("*").unbind(".OutsideMenus"); }); $("#menuscontainer").bind("click.OutsideMenus", function (event) { event.stopPropagation(); }); |
1 2 3 4 5 6 7 8 9 10 11 12 | jQuery().ready(function(){ $('#nav').click(function (event) { $(this).addClass('activ'); event.stopPropagation(); }); $('html').click(function () { if( $('#nav').hasClass('activ') ){ $('#nav').removeClass('activ'); } }); }); |
这是我的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | // Listen to every click $('html').click(function(event) { if ( $('#mypopupmenu').is(':visible') ) { if (event.target.id != 'click_this_to_show_mypopupmenu') { $('#mypopupmenu').hide(); } } }); // Listen to selector's clicks $('#click_this_to_show_mypopupmenu').click(function() { // If the menu is visible, and you clicked the selector again we need to hide if ( $('#mypopupmenu').is(':visible') { $('#mypopupmenu').hide(); return true; } // Else we need to show the popup menu $('#mypopupmenu').show(); }); |
这对我有用
1 2 3 4 5 6 | $("body").mouseup(function(e) { var subject = $(".main-menu"); if(e.target.id != subject.attr('id') && !subject.has(e.target).length) { $('.sub-menu').hide(); } }); |
1 2 3 4 5 6 7 8 9 10 11 12 | $(document).on("click",function (event) { console.log(event); if ($(event.target).closest('.element').length == 0) { //your code here if ($(".element").hasClass("active")) { $(".element").removeClass("active"); } } }); |
尝试此编码以获取解决方案。
对于iPad和iPhone等触摸设备,我们可以使用以下代码:
1 2 3 4 5 6 7 8 9 | $(document).on('touchstart', function (event) { var container = $("YOUR CONTAINER SELECTOR"); if (!container.is(e.target) && // If the target of the click isn't the container... container.has(e.target).length === 0) // ... nor a descendant of the container { container.hide(); } }); |
如果您使用"弹出"等工具,则可以使用"onfocusout"事件。
1 2 3 4 5 6 | window.onload=function(){ document.getElementById("inside-div").focus(); } function loseFocus(){ alert("Clicked outside"); } |
1 2 3 4 5 6 7 8 9 10 11 12 | #container{ background-color:lightblue; width:200px; height:200px; } #inside-div{ background-color:lightgray; width:100px; height:100px; } |
1 | <input type="text" id="inside-div" onfocusout="loseFocus()"> |
我知道这个问题有很多答案,但我一直很喜欢用HTML和CSS来完成大部分工作。在这种情况下,Z-索引和定位。我发现最简单的方法如下:
1 2 3 4 5 6 7 8 | $("#show-trigger").click(function(){ $("#element").animate({width: 'toggle'}); $("#outside-element").show(); }); $("#outside-element").click(function(){ $("#element").hide(); $("#outside-element").hide(); }); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #outside-element { position:fixed; width:100%; height:100%; z-index:1; display:none; } #element { display:none; padding:20px; background-color:#ccc; width:300px; z-index:2; position:relative; } #show-trigger { padding:20px; background-color:#ccc; margin:20px auto; z-index:2; } |
1 2 3 4 5 6 7 8 9 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"> Menu Item 1 Menu Item 1 Menu Item 1 Menu Item 1 Show Menu |
这就创建了一个安全的环境,因为除非菜单实际上是打开的,否则不会触发任何操作,而且z索引可以保护元素中的任何内容在被单击时不会产生任何错误。
此外,您不需要jquery用传播调用覆盖所有的基,并且必须清除所有内部元素中的缺火。
标记为已接受答案的答案没有考虑到您可以在元素上有覆盖,如对话框、弹出窗口、日期选取器等。单击这些选项不应隐藏元素。
我自己做的版本确实考虑到了这一点。它是作为一个knockoutJS绑定创建的,但是它可以很容易地转换为jquery。
它通过第一次查询所有具有z索引或绝对位置可见的元素来工作。然后,它会根据我想要隐藏的元素测试这些元素,如果单击外部。如果是命中,我会计算一个新的绑定矩形,考虑到覆盖边界。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | ko.bindingHandlers.clickedIn = (function () { function getBounds(element) { var pos = element.offset(); return { x: pos.left, x2: pos.left + element.outerWidth(), y: pos.top, y2: pos.top + element.outerHeight() }; } function hitTest(o, l) { function getOffset(o) { for (var r = { l: o.offsetLeft, t: o.offsetTop, r: o.offsetWidth, b: o.offsetHeight }; o = o.offsetParent; r.l += o.offsetLeft, r.t += o.offsetTop); return r.r += r.l, r.b += r.t, r; } for (var b, s, r = [], a = getOffset(o), j = isNaN(l.length), i = (j ? l = [l] : l).length; i; b = getOffset(l[--i]), (a.l == b.l || (a.l > b.l ? a.l <= b.r : b.l <= a.r)) && (a.t == b.t || (a.t > b.t ? a.t <= b.b : b.t <= a.b)) && (r[r.length] = l[i])); return j ? !!r.length : r; } return { init: function (element, valueAccessor) { var target = valueAccessor(); $(document).click(function (e) { if (element._clickedInElementShowing === false && target()) { var $element = $(element); var bounds = getBounds($element); var possibleOverlays = $("[style*=z-index],[style*=absolute]").not(":hidden"); $.each(possibleOverlays, function () { if (hitTest(element, this)) { var b = getBounds($(this)); bounds.x = Math.min(bounds.x, b.x); bounds.x2 = Math.max(bounds.x2, b.x2); bounds.y = Math.min(bounds.y, b.y); bounds.y2 = Math.max(bounds.y2, b.y2); } }); if (e.clientX < bounds.x || e.clientX > bounds.x2 || e.clientY < bounds.y || e.clientY > bounds.y2) { target(false); } } element._clickedInElementShowing = false; }); $(element).click(function (e) { e.stopPropagation(); }); }, update: function (element, valueAccessor) { var showing = ko.utils.unwrapObservable(valueAccessor()); if (showing) { element._clickedInElementShowing = true; } } }; })(); |
我相信最好的方法就是这样。
1 2 3 4 | $(document).on("click", function(event) { clickedtarget = $(event.target).closest('#menuscontainer'); $("#menuscontainer").not(clickedtarget).hide(); }); |
这种类型的解决方案可以很容易地用于多个菜单以及通过javascript动态添加的菜单。基本上,它只允许您单击文档中的任意位置,检查您单击的元素,并选择最接近的"menusContainer"。然后它隐藏所有menusContainers,但不包括您单击的内容。
不确定菜单是如何构建的,但可以在jfiddle中复制我的代码。这是一个非常简单但功能齐全的菜单/模式系统。您所需要做的就是构建HTML菜单,代码将为您完成这项工作。
https://jsfiddle.net/zs6anrn7/
对某些人来说,这可能是个更好的解决办法。
1 2 3 4 5 6 7 | $(".menu_link").click(function(){ // show menu code }); $(".menu_link").mouseleave(function(){ //hide menu code, you may add a timer for 3 seconds before code to be run }); |
我知道mouseleave不仅意味着单击外部,还意味着离开元素的区域。
一旦菜单本身在
简单的插件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | $.fn.clickOff = function(callback, selfDestroy) { var clicked = false; var parent = this; var destroy = selfDestroy || true; parent.click(function() { clicked = true; }); $(document).click(function(event) { if (!clicked && parent.is(':visible')) { if(callback) callback.call(parent, event) } if (destroy) { //parent.clickOff = function() {}; //parent.off("click"); //$(document).off("click"); parent.off("clickOff"); } clicked = false; }); }; |
使用:
1 2 3 | $("#myDiv").clickOff(function() { alert('clickOff'); }); |
如果clicked外大
1 2 3 4 5 6 7 8 | jQuery(document).mouseup(function (e) { var container = $(".fileTreeClass"); if (!container.is(e.target) // if the target of the click isn't the container... && container.has(e.target).length === 0) // ... nor a descendant of the container { container.hide(); } }); |
假设您要检测用户单击的外部或内部是否具有ID的DIV,例如:"我的特殊小部件"。
收听Body Click事件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | document.body.addEventListener('click', (e) => { if (isInsideMySpecialWidget(e.target,"my-special-widget")) { console.log("user clicked INSIDE the widget"); } console.log("user clicked OUTSIDE the widget"); }); function isInsideMySpecialWidget(elem, mySpecialWidgetId){ while (elem.parentElement) { if (elem.id === mySpecialWidgetId) { return true; } elem = elem.parentElement; } return false; } |
在这种情况下,不会破坏页面中某个元素的正常单击流,因为您没有使用"stoppropagation"方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | $('#propertyType').on("click",function(e){ self.propertyTypeDialog = !self.propertyTypeDialog; b = true; e.stopPropagation(); console.log("input clicked"); }); $(document).on('click','body:not(#propertyType)',function (e) { e.stopPropagation(); if(b == true) { if ($(e.target).closest("#configuration").length == 0) { b = false; self.propertyTypeDialog = false; console.log("outside clicked"); } } // console.log($(e.target).closest("#configuration").length); }); |
试试这个:
1 2 3 4 5 | $('html').click(function(e) { if($(e.target).parents('#menuscontainer').length == 0) { $('#menuscontainer').hide(); } }); |
https://jsfiddle.net/4cj4jxy0/
但请注意,如果click事件不能到达
如果您只想在单击按钮时显示一个窗口,而在单击外部时取消显示该窗口(或再次单击按钮),则下面的内容很好
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | document.body.onclick = function() { undisp_menu(); }; var menu_on = 0; function menu_trigger(event){ if (menu_on == 0) { // otherwise u will call the undisp on body when // click on the button event.stopPropagation(); disp_menu(); } else{ undisp_menu(); } } function disp_menu(){ menu_on = 1; var e = document.getElementsByClassName("menu")[0]; e.className ="menu on"; } function undisp_menu(){ menu_on = 0; var e = document.getElementsByClassName("menu")[0]; e.className ="menu"; } |
别忘了这个按钮
1 |
CSS:
1 2 3 4 5 6 7 | .menu{ display: none; } .on { display: inline-block; } |
订阅点击捕获阶段,处理调用
1 2 3 4 5 | document.addEventListener('click', function (event) { event = $.event.fix(event); event.type = 'click-anywhere'; $document.trigger(event); }, true); |
然后,如果需要单击外部功能,请订阅
1 2 3 4 5 | $(document).on('click-anywhere', function (event) { if (!$(event.target).closest('#smth').length) { // Do anything you need here } }); |
一些注释:
您必须使用
document ,因为它将是一个性能错误,在发生单击的所有元素上触发事件。这个功能可以被包装成特殊的插件,它在外部单击时调用一些回调。
不能使用jquery本身订阅捕获阶段。
由于订阅在
document 上,甚至不在其body 上,所以订阅不需要文档加载,因此它始终独立存在于脚本放置和加载状态。
1 2 3 4 5 6 7 | $('html').click(function() { //Hide the menus if visible }); $('#menucontainer').click(function(event){ event.stopPropagation(); }); |
1 2 3 4 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"> <html> <button id='#menucontainer'>Ok</button> </html> |
1 2 3 4 5 6 7 | $('#menucontainer').click(function(e){ e.stopPropagation(); }); $(document).on('click', function(e){ // code }); |
只是一个警告:
1 2 3 4 5 6 7 | $('html').click(function() { // Hide the menus if visible }); $('#menucontainer').click(function(event){ event.stopPropagation(); }); |
它会阻止RubyonRails UJS驱动程序正常工作。例如,
这可能是一个解决方法:
1 2 3 4 5 6 7 8 9 | $('html').click(function() { // Hide the menus if visible }); $('#menucontainer').click(function(event){ if (!$(event.target).data('method')) { event.stopPropagation(); } }); |
这将在单击元素时切换导航菜单。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | $(document).on('click', function(e) { var elem = $(e.target).closest('#menu'), box = $(e.target).closest('#nav'); if (elem.length) { e.preventDefault(); $('#nav').toggle(); } else if (!box.length) { $('#nav').hide(); } }); <li id="menu"> </li> <ul id="nav"> //Nav will toggle when you Click on Menu(it can be an icon in this example) <li class="page">Page1 </li> <li class="page">Pag2 </li> <li class="page">Page3 </li> <li class="page">Page4 </li> </ul> |
这是一个更通用的解决方案,允许监视多个元素,并动态地添加和删除队列中的元素。
它包含一个全局队列(autoclosequeue)——一个对象容器,用于在外部单击时关闭元素。
每个队列对象键都应该是dom元素id,并且该值应该是具有两个回调函数的对象:
1 | {onPress: someCallbackFunction, onOutsidePress: anotherCallbackFunction} |
将其放入文档就绪回调:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | window.autoCloseQueue = {} $(document).click(function(event) { for (id in autoCloseQueue){ var element = autoCloseQueue[id]; if ( ($(e.target).parents('#' + id).length) > 0) { // This is a click on the element (or its child element) console.log('This is a click on an element (or its child element) with id: ' + id); if (typeof element.onPress == 'function') element.onPress(event, id); } else { //This is a click outside the element console.log('This is a click outside the element with id: ' + id); if (typeof element.onOutsidePress == 'function') element.onOutsidePress(event, id); //call the outside callback delete autoCloseQueue[id]; //remove the element from the queue } } }); |
然后,当创建ID为"menuscontainer"的dom元素时,只需将此对象添加到队列:
1 | window.autoCloseQueue['menuscontainer'] = {onOutsidePress: clickOutsideThisElement} |
1 2 3 4 5 6 7 8 9 | $(document).on('click.menu.hide', function(e){ if ( !$(e.target).closest('#my_menu').length ) { $('#my_menu').find('ul').toggleClass('active', false); } }); $(document).on('click.menu.show', '#my_menu li', function(e){ $(this).find('ul').toggleClass('active'); }); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | div { float: left; } ul { padding: 0; position: relative; } ul li { padding: 5px 25px 5px 10px; border: 1px solid silver; cursor: pointer; list-style: none; margin-top: -1px; white-space: nowrap; } ul li ul:before { margin-right: -20px; position: absolute; top: -17px; right: 0; content:"\25BC"; } ul li ul li { visibility: hidden; height: 0; padding-top: 0; padding-bottom: 0; border-width: 0 0 1px 0; } ul li ul li:last-child { border: none; } ul li ul.active:before { content:"\25B2"; } ul li ul.active li { display: list-item; visibility: visible; height: inherit; padding: 5px 25px 5px 10px; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | <script src="https://code.jquery.com/jquery-2.1.4.js"> <ul id="my_menu"> <li> Menu 1 <ul> <li> subMenu 1 </li> <li> subMenu 2 </li> <li> subMenu 3 </li> <li> subMenu 4 </li> </ul> </li> <li> Menu 2 <ul> <li> subMenu 1 </li> <li> subMenu 2 </li> <li> subMenu 3 </li> <li> subMenu 4 </li> </ul> </li> <li> Menu 3 </li> <li> Menu 4 </li> <li> Menu 5 </li> <li> Menu 6 </li> </ul> |
这里是jsbin版本http://jsbin.com/xopacadeni/edit?HTML、CSS、JS、输出
外部点击插件!
用途:
1 2 3 4 5 | $('.target-element').outsideClick(function(event){ //code that fires when user clicks outside the element //event = the click event //$(this) = the '.target-element' that is firing this function }, '.excluded-element') |
它的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | (function($) { //when the user hits the escape key, it will trigger all outsideClick functions $(document).on("keyup", function (e) { if (e.which == 27) $('body').click(); //escape key }); //The actual plugin $.fn.outsideClick = function(callback, exclusions) { var subject = this; //test if exclusions have been set var hasExclusions = typeof exclusions !== 'undefined'; //switches click event with touch event if on a touch device var ClickOrTouchEvent ="ontouchend" in document ?"touchend" :"click"; $('body').on(ClickOrTouchEvent, function(event) { //click target does not contain subject as a parent var clickedOutside = !$(event.target).closest(subject).length; //click target was on one of the excluded elements var clickedExclusion = $(event.target).closest(exclusions).length; var testSuccessful; if (hasExclusions) { testSuccessful = clickedOutside && !clickedExclusion; } else { testSuccessful = clickedOutside; } if(testSuccessful) { callback.call(subject, event); } }); return this; }; }(jQuery)); |
改编自此答案https://stackoverflow.com/a/3028037/1611058
使用NOT():
1 2 3 | $("#id").not().click(function() { alert('Clicked other that #id'); }); |
可以将tabindex设置为dom元素。当用户单击dom元素外部时,这将触发一个模糊事件。
演示
1 2 3 4 5 6 7 8 9 | Focus me document.querySelector("div").onblur = function(){ console.log('clicked outside') } document.querySelector("div").onfocus = function(){ console.log('clicked inside') } |
作为ART这个伟大答案的包装,为了使用OP最初请求的语法,这里有一个jquery扩展,可以记录在set元素之外是否发生了单击。
1 2 3 4 5 6 7 8 9 10 | $.fn.clickOutsideThisElement = function (callback) { return this.each(function () { var self = this; $(document).click(function (e) { if (!$(e.target).closest(self).length) { callback.call(self, e) } }) }); }; |
然后你可以这样叫:
1 2 3 | $("#menuscontainer").clickOutsideThisElement(function() { // handle menu toggle }); |
这是一个小提琴的演示
这是一个经典的例子,其中对HTML的调整将是一个更好的解决方案。为什么不设置单击不包含菜单项的元素?那么就不需要添加传播了。
1 2 3 | $('.header, .footer, .main-content').click(function() { //Hide the menus if visible }); |
1 2 3 4 5 6 7 8 | function hidefeedback(){ $j(".feedbackhide").hide(); } function showfeedback(){ $j(".feedbackhide").show(); $j(".feedbackCont").attr("tabindex",1).focus(); } |
这是我提出的最简单的解决方案。
试试这个代码:
1 2 3 4 5 6 7 | if ($(event.target).parents().index($('#searchFormEdit')) == -1 && $(event.target).parents().index($('.DynarchCalendar-topCont')) == -1 && (_x < os.left || _x > (os.left + 570) || _y < os.top || _y > (os.top + 155)) && isShowEditForm) { setVisibleEditForm(false); } |
1 2 3 | $("body > div:not(#dvid)").click(function (e) { //your code }); |
1 2 3 4 5 | $("html").click(function(){ if($('#info').css("opacity")>0.9) { $('#info').fadeOut('fast'); } }); |
标准HTML:
用
http://jsfiddle.net/bk3gl/
另外:您可以通过tabkbbkbd展开菜单。