JQuery检测单击外部元素并停止所有其他单击事件

时间:2017-08-17 13:40:06

标签: javascript jquery

我正在制作一个弹出菜单。用户点击它以显示菜单,然后如果他们在弹出菜单外单击我想隐藏它。

我可以找到很多解决方案(最流行的是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事件本身,那么该代码仍会被触发。在树下方的元素甚至可以首先获得点击,因此我无法使用preventDefaultstopPropagation来停止这些事件。

任何想法如何解决?我唯一的想法是在整个屏幕上放置一个透明的div,以便首先捕获点击次数?

3 个答案:

答案 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;
&#13;
&#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用于附加事件处理程序的用法。它在执行一次后自动删除事件处理程序。

参考https://api.jquery.com/one/