我有一些HTML菜单,当用户单击这些菜单的头部时,我会完全显示这些菜单。当用户在菜单区域外单击时,我希望隐藏这些元素。
jQuery是否可以实现这样的功能?
$("#menuscontainer").clickOutsideThisElement(function() {
// Hide the menus
});
我有一些HTML菜单,当用户单击这些菜单的头部时,我会完全显示这些菜单。当用户在菜单区域外单击时,我希望隐藏这些元素。
jQuery是否可以实现这样的功能?
$("#menuscontainer").clickOutsideThisElement(function() {
// Hide the menus
});
当前回答
这是我对这个问题找到的最简单的答案:
window.addEventListener('click', close_window = function () {
if(event.target !== windowEl){
windowEl.style.display = "none";
window.removeEventListener('click', close_window, false);
}
});
您将看到我将函数命名为“close_window”,以便在窗口关闭时删除事件侦听器。
其他回答
投票选出最受欢迎的答案,但添加
&& (e.target != $('html').get(0)) // ignore the scrollbar
因此,单击滚动条不会隐藏目标元素。
使用not():
$("#id").not().click(function() {
alert('Clicked other that #id');
});
使用流中断、模糊/聚焦事件或任何其他棘手的技术,只需将事件流与元素的亲属关系匹配即可:
$(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");
您可以监听文档上的单击事件,然后使用.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()
}
}
这是一个容器或整个文档中的解决方案。若click目标在元素之外(类为“yourClass”),则元素被隐藏。
$('yourContainer').on('click', function(e) {
if (!$(e.target).hasClass('yourClass')) {
$('.yourClass').hide();
}
});