简体   繁体   English

jQuery检测外部点击事件并停止所有其他点击事件

[英]JQuery detect click outside element and stop all other click events

I'm making a popup menu. 我正在制作一个弹出菜单。 The user clicks on it to show the menu, then if they click outside the popup menu I want to hide it. 用户单击它以显示菜单,然后如果他们在弹出菜单之外单击,我想将其隐藏。

I can find many solutions (most popular is here: How do I detect a click outside an element? ) but they all seem to have the same issue. 我可以找到许多解决方案(最受欢迎的解决方案是: 如何检测元素外部的点击? ),但是它们似乎都存在相同的问题。

They rely on handling clicks that bubble up to the window element. 他们依靠处理气泡到窗口元素的点击。

Their Logic: 他们的逻辑:

All clicks bubble up to window element. 所有单击都会冒泡到窗口元素。 Handle those clicks - if menu is open, then close it. 处理这些单击-如果菜单已打开,则将其关闭。 Also call preventDefault to stop any links being followed (let's just say that the user happens to click on a link when they are clicking outside the menu - we don't want to follow that link) 也可以调用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');
            }
        }
    });

The issue 问题

If the thing the user clicks on happens to have an onclick event itself then that code still gets fired. 如果用户单击的内容恰好本身具有onclick事件,则该代码仍会被触发。 Elements lower down the tree get the click even first, so I cannot use preventDefault or stopPropagation to stop these events.. 树下的元素甚至会先获得点击,因此我无法使用preventDefaultstopPropagation来停止这些事件。

Any ideas how to fix it? 任何想法如何解决? My only idea is to put a transparent div across the whole screen on top of everything to catch the clicks first? 我唯一的想法是在整个屏幕上放置一个透明的div,以首先捕获点击?

You need to use addEventListener() and the useCapture property. 您需要使用addEventListener()useCapture属性。 the useCapture property allows events from object higher in the DOM tree to be triggered first. useCapture属性允许首先触发DOM树中较高对象的事件。 You can then prevent your normal click behaviour from occurring: 然后,您可以防止发生正常的点击行为:

 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); 
 <!DOCTYPE html> <html lang="en"> <head> </head> <body> <button id="myButton">Hello!</button> <div id="myResponse">Who Clicked?</div> </body> </html> 

Updated 更新

I originally misunderstood that we were trying to stop inline onclick events from firing. 我最初误解为我们试图阻止触发内联onclick事件。 I found a potential solution from another StackOverflow question, you can see it here . 我从另一个StackOverflow问题中找到了可能的解决方案,您可以在此处查看

Otherwise, take a look at this: 否则,请看以下内容:

 $('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);
    };
 });

It overrides the elements click handler. 它会覆盖元素单击处理程序。 I've updated your jsFiddle to show it in action. 我已经更新了您的jsFiddle来展示其实际效果。

you can add a class to the body when menu is opened, and attach an event listener to the click event of body which will hide the menu and remove the listener 您可以在打开菜单时向主体添加一个类,并将事件侦听器附加到主体的click事件,这将隐藏菜单并删除侦听器

when showing the menu 显示菜单时

$('body').addClass('menu-open');
$('body.menu-open').one('click', function(e) {
    e.preventDefault();
    // code to hide your menu goes here
    $('body').removeClass('menu-open');
});

Note the usage of .one for attaching the event handler. 注意使用.one附加事件处理程序。 It automatically removes the event handler after it is executed once. 执行一次后,它将自动删除事件处理程序。

Ref https://api.jquery.com/one/ 引用https://api.jquery.com/one/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM