我正在制作一个弹出菜单。用户点击它以显示菜单,然后如果他们在弹出菜单外单击我想隐藏它。
我可以找到很多解决方案(最流行的是How do I detect a click outside an element?),但它们似乎都有同样的问题。
他们依赖于处理冒泡到窗口元素的点击。
他们的逻辑:
所有点击都会冒泡到窗口元素。处理这些点击 - 如果菜单已打开,则关闭它。同时致电preventDefault
以停止跟踪任何链接(我们只是说当用户点击菜单外的链接时,我们不想关注该链接)
$(window).click(function(e) {
if (!e.isDefaultPrevented()) {
if($('.mainNav').hasClass('menuVisible')){
//stop any other actions happening (e.g. following a link)
e.preventDefault();
//Hide the menus
$('.mainNav').removeClass('menuVisible');
}
}
});
问题
如果用户点击的内容恰好有onclick
事件本身,那么该代码仍会被触发。在树下方的元素甚至可以首先获得点击,因此我无法使用preventDefault
或stopPropagation
来停止这些事件。
任何想法如何解决?我唯一的想法是在整个屏幕上放置一个透明的div,以便首先捕获点击次数?
答案 0 :(得分:1)
您需要使用addEventListener()
和useCapture
属性。 useCapture属性允许首先触发DOM树中较高对象的事件。然后,您可以阻止发生正常的点击行为:
var button = document.getElementById("myButton");
var response = document.getElementById("myResponse");
var windowClick = function (evt) {
response.innerHTML += "<p>The Window</p>";
evt.stopPropagation ();
}
var buttonClick = function (evt) {
response.innerHTML += "<p>The Button</p>";
evt.stopPropagation ();
}
button.addEventListener("click", buttonClick);
// If true, the window event fires first, if false, the button fires first.
var useCapture = true;
window.addEventListener("click", windowClick, useCapture);
&#13;
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<button id="myButton">Hello!</button>
<div id="myResponse">Who Clicked?</div>
</body>
</html>
&#13;
答案 1 :(得分:1)
<强>更新强>
我最初误解了我们试图阻止内联攻击事件发射。我从另一个StackOverflow问题中找到了一个潜在的解决方案,你可以看到它here。
否则,请看一下:
$('button[onclick]').each(function(){
$(this).data('onclick', this.onclick);
this.onclick = function(event) {
if($('.mainNav').hasClass('menuVisible')) {
return false;
};
$(this).data('onclick').call(this, event || window.event);
};
});
它会覆盖元素click handler。我已经updated your jsFiddle展示了它的实际效果。
答案 2 :(得分:0)
您可以在打开菜单时向正文添加一个类,并将事件侦听器附加到正文的click事件,这将隐藏菜单并删除侦听器
显示菜单时
$('body').addClass('menu-open');
$('body.menu-open').one('click', function(e) {
e.preventDefault();
// code to hide your menu goes here
$('body').removeClass('menu-open');
});
请注意.one
用于附加事件处理程序的用法。它在执行一次后自动删除事件处理程序。