我有一些HTML菜单,当用户单击这些菜单的头部时,我会完全显示这些菜单。当用户在菜单区域外单击时,我希望隐藏这些元素。
jQuery是否可以实现这样的功能?
$("#menuscontainer").clickOutsideThisElement(function() {
// Hide the menus
});
我有一些HTML菜单,当用户单击这些菜单的头部时,我会完全显示这些菜单。当用户在菜单区域外单击时,我希望隐藏这些元素。
jQuery是否可以实现这样的功能?
$("#menuscontainer").clickOutsideThisElement(function() {
// Hide the menus
});
当前回答
如果有人好奇这里是javascript解决方案(es6):
window.addEventListener('mouseup', e => {
if (e.target != yourDiv && e.target.parentNode != yourDiv) {
yourDiv.classList.remove('show-menu');
//or yourDiv.style.display = 'none';
}
})
和es5,以防万一:
window.addEventListener('mouseup', function (e) {
if (e.target != yourDiv && e.target.parentNode != yourDiv) {
yourDiv.classList.remove('show-menu');
//or yourDiv.style.display = 'none';
}
});
其他回答
$(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');
});
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;
}
<script src="https://code.jquery.com/jquery-2.1.4.js"></script>
<div>
<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>
</div>
这里是jsbin版本http://jsbin.com/xopacadeni/edit?html,css,js,输出
使用流中断、模糊/聚焦事件或任何其他棘手的技术,只需将事件流与元素的亲属关系匹配即可:
$(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)
}
});
要删除事件侦听器外部的单击,只需执行以下操作:
$(document).off("click.menu-outside");
标准HTML:
用<标签>包围菜单并获取焦点状态更改。
http://jsfiddle.net/bK3gL/
另外:您可以通过Tab展开菜单。
这是我的代码:
// 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();
});
您可以监听文档上的单击事件,然后使用.clost()确保#menucontainer不是被单击元素的祖先或目标。
如果不是,则单击的元素位于#menucontainer之外,您可以安全地隐藏它。
$(document).click(function(event) {
var $target = $(event.target);
if(!$target.closest('#menucontainer').length &&
$('#menucontainer').is(":visible")) {
$('#menucontainer').hide();
}
});
编辑–2017-06-23
如果您计划关闭菜单并希望停止侦听事件,也可以在事件侦听器之后进行清理。此函数将只清理新创建的侦听器,保留文档上的任何其他单击侦听器。使用ES2015语法:
export function hideOnClickOutside(selector) {
const outsideClickListener = (event) => {
const $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)代码。
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的评论,仅供使用!元素。包含(event.target)而不是jQuery部分。
但是element.clost()现在也可以在所有主要浏览器中使用(W3C版本与jQuery版本稍有不同)。Polyfills可以在以下位置找到:Element.clost()
编辑–2020-05-21
如果您希望用户能够在元素内部单击并拖动,则在元素外部释放鼠标,而不关闭元素:
...
let lastMouseDownX = 0;
let lastMouseDownY = 0;
let lastMouseDownWasOutside = false;
const mouseDownListener = (event: MouseEvent) => {
lastMouseDownX = event.offsetX;
lastMouseDownY = event.offsetY;
lastMouseDownWasOutside = !$(event.target).closest(element).length;
}
document.addEventListener('mousedown', mouseDownListener);
在外部ClickListener中:
const outsideClickListener = event => {
const deltaX = event.offsetX - lastMouseDownX;
const deltaY = event.offsetY - lastMouseDownY;
const distSq = (deltaX * deltaX) + (deltaY * deltaY);
const isDrag = distSq > 3;
const isDragException = isDrag && !lastMouseDownWasOutside;
if (!element.contains(event.target) && isVisible(element) && !isDragException) { // or use: event.target.closest(selector) === null
element.style.display = 'none';
removeClickListener();
document.removeEventListener('mousedown', mouseDownListener); // Or add this line to removeClickListener()
}
}