我有一些HTML菜单,当用户单击这些菜单的头部时,我会完全显示这些菜单。当用户在菜单区域外单击时,我希望隐藏这些元素。
jQuery是否可以实现这样的功能?
$("#menuscontainer").clickOutsideThisElement(function() {
// Hide the menus
});
我有一些HTML菜单,当用户单击这些菜单的头部时,我会完全显示这些菜单。当用户在菜单区域外单击时,我希望隐藏这些元素。
jQuery是否可以实现这样的功能?
$("#menuscontainer").clickOutsideThisElement(function() {
// Hide the menus
});
当前回答
单击元素时,这将切换导航菜单。
$(document).on('click',函数(e){var elem=$(e.target).最近('#menu'),box=$(e.target).最近('#nav');if(元素长度){e.预防违约();$('#nav').tggle();}否则如果(!box.length){$('#nav').hide();}});<script src=“https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js“></script><li id=“menu”><a></a></li><ul id=“nav”><!--单击菜单时,导航将切换(在本例中它可以是一个图标)--><li class=“page”><a>第1页</a></li><li class=“page”><a>第2页</a></li><li class=“page”><a>第3页</a></li><li class=“page”><a>第4页</a></li></ul>
其他回答
我认为最好的方法是这样做。
$(document).on("click", function(event) {
clickedtarget = $(event.target).closest('#menuscontainer');
$("#menuscontainer").not(clickedtarget).hide();
});
这种类型的解决方案很容易适用于多个菜单以及通过javascript动态添加的菜单。基本上,它只允许您单击文档中的任何位置,并检查您单击的元素,并选择最接近的“#菜单容器”。然后它会隐藏所有菜单容器,但不包括您单击的菜单容器。
不确定菜单是如何构建的,但可以在JSFiddle中复制我的代码。这是一个非常简单但功能全面的菜单/模式系统。您需要做的就是构建html菜单,代码将为您完成这项工作。
https://jsfiddle.net/zs6anrn7/
在文档上挂起一个单击事件侦听器。在事件侦听器中,您可以查看事件对象,特别是event.target,以查看单击了什么元素:
$(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");
}
});
现在有一个插件:外部事件(博客文章)
当clickoutside处理程序(WLOG)绑定到元素时,会发生以下情况:
元素被添加到一个数组中,该数组包含所有具有clickoutside处理程序的元素(名称空间)单击处理程序绑定到文档(如果尚未存在)在文档中的任何单击时,都会为该数组中不等于或不是单击事件目标的父级的元素触发单击外部事件此外,clickoutside事件的event.target设置为用户单击的元素(因此您甚至可以知道用户单击了什么,而不仅仅是他在外面单击了什么)
因此,不会阻止任何事件的传播,并且可以在元素的“上方”使用额外的单击处理程序和外部处理程序。
检查窗口单击事件目标(它应该传播到窗口,只要它没有在其他地方被捕获),并确保它不是任何菜单元素。如果不是,那么你就在菜单之外。
或者检查单击的位置,看看它是否包含在菜单区域中。
标记为接受答案的答案没有考虑到元素上可以有覆盖,如对话框、弹出窗口、日期选择器等。单击这些按钮不应隐藏元素。
我制作了自己的版本,确实考虑到了这一点。它是作为KnockoutJS绑定创建的,但它可以很容易地仅转换为jQuery。
它通过第一次查询所有具有z索引或绝对位置的可见元素来工作。然后,如果在外部单击,它会根据我想要隐藏的元素来测试这些元素。如果是命中,我会计算一个新的边界矩形,该矩形考虑到覆盖边界。
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;
}
}
};
})();