检测元素外的点击(vanilla JavaScript)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14188654/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Detect click outside element (vanilla JavaScript)
提问by Tiberiu-Ionu? Stan
I have searched for a good solution everywhere, yet I can't find one which does not use jQuery.
我到处都在寻找一个好的解决方案,但我找不到一个不使用 jQuery 的解决方案。
Is there a cross-browser, normal way (without weird hacks or easy to break code), to detect a click outside of an element (which may or may not have children)?
是否有跨浏览器的正常方式(没有奇怪的黑客或容易破坏的代码)来检测元素外部的点击(可能有也可能没有孩子)?
回答by fregante
Add an event listener to documentand use Node.contains()to find whether the target of the event (which is the inner-most clicked element) is inside your specified element. It works even in IE5
添加事件侦听器document并用于Node.contains()查找事件的目标(即最内层点击的元素)是否在您指定的元素内。它甚至在 IE5 中也能工作
var specifiedElement = document.getElementById('a');
//I'm using "click" but it works with any event
document.addEventListener('click', function(event) {
var isClickInside = specifiedElement.contains(event.target);
if (!isClickInside) {
//the click was outside the specifiedElement, do something
}
});
var specifiedElement = document.getElementById('a');
//I'm using "click" but it works with any event
document.addEventListener('click', function(event) {
var isClickInside = specifiedElement.contains(event.target);
if (isClickInside) {
alert('You clicked inside A')
} else {
alert('You clicked outside A')
}
});
div {
margin: auto;
padding: 1em;
max-width: 6em;
background: rgba(0, 0, 0, .2);
text-align: center;
}
Is the click inside A or outside?
<div id="a">A
<div id="b">B
<div id="c">C</div>
</div>
</div>
回答by metadings
You need to handle the click event on document level. In the event object, you have a targetproperty, the inner-most DOM element that was clicked. With this you check itself and walk up its parents until the document element, if one of them is your watched element.
您需要在文档级别处理单击事件。在事件对象中,您有一个target属性,即被单击的最内部 DOM 元素。有了这个,您可以检查自己并向上走,直到文档元素,如果其中一个是您观看的元素。
See the example on jsFiddle
document.addEventListener("click", function (e) {
var level = 0;
for (var element = e.target; element; element = element.parentNode) {
if (element.id === 'x') {
document.getElementById("out").innerHTML = (level ? "inner " : "") + "x clicked";
return;
}
level++;
}
document.getElementById("out").innerHTML = "not x clicked";
});
As always, this isn't cross-bad-browser compatible because of addEventListener/attachEvent, but it works like this.
与往常一样,由于 addEventListener/attachEvent,这不是跨坏浏览器兼容的,但它的工作原理是这样的。
A child is clicked, when not event.target, but one of it's parents is the watched element (i'm simply counting level for this). You may also have a boolean var, if the element is found or not, to not return the handler from inside the for clause. My example is limiting to that the handler only finishes, when nothing matches.
当不是 event.target 时,一个孩子被点击,但它的父母之一是被监视的元素(我只是为此计算级别)。你也可能有一个布尔变量,如果元素被找到与否,则不从 for 子句内部返回处理程序。我的示例仅限于处理程序仅在没有匹配项时完成。
Adding cross-browser compatability, I'm usually doing it like this:
添加跨浏览器兼容性,我通常是这样做的:
var addEvent = function (element, eventName, fn, useCapture) {
if (element.addEventListener) {
element.addEventListener(eventName, fn, useCapture);
}
else if (element.attachEvent) {
element.attachEvent(eventName, function (e) {
fn.apply(element, arguments);
}, useCapture);
}
};
This is cross-browser compatible code for attaching an event listener/handler, inclusive rewriting thisin IE, to be the element, as like jQuery does for its event handlers. There are plenty of arguments to have some bits of jQuery in mind ;)
这是跨浏览器兼容的代码,用于附加事件侦听器/处理程序,this在 IE 中包含重写,作为元素,就像 jQuery 为其事件处理程序所做的那样。有很多论据可以考虑一些 jQuery ;)
回答by Akhil Sekharan
How about this:
这个怎么样:
document.onclick = function(event){
var hasParent = false;
for(var node = event.target; node != document.body; node = node.parentNode)
{
if(node.id == 'div1'){
hasParent = true;
break;
}
}
if(hasParent)
alert('inside');
else
alert('outside');
}
回答by Aleks Sid
To hide element by click outside of it I usually apply such simple code:
要通过在元素外部单击来隐藏元素,我通常会应用这样简单的代码:
var bodyTag = document.getElementsByTagName('body');
var element = document.getElementById('element');
function clickedOrNot(e) {
if (e.target !== element) {
// action in the case of click outside
bodyTag[0].removeEventListener('click', clickedOrNot, true);
}
}
bodyTag[0].addEventListener('click', clickedOrNot, true);
回答by hpapier
Another very simple and quick approach to this problem is to map the array of pathinto the event object returned by the listener. If the idor classname of your element matches one of those in the array, the click is inside your element.
解决这个问题的另一种非常简单快捷的方法是将 的数组映射path到侦听器返回的事件对象中。如果您的元素的id或class名称与数组中的其中一个匹配,则单击位于您的元素内。
(This solution can be useful if you don't want to get the element directly (e.g: document.getElementById('...'), for example in a reactjs/nextjs app, in ssr..).
(如果您不想直接获取元素,此解决方案会很有用(例如:document.getElementById('...'),例如在 reactjs/nextjs 应用程序中,在 ssr 中...)。
Here is an example:
下面是一个例子:
document.addEventListener('click', e => {
let clickedOutside = true;
e.path.forEach(item => {
if (!clickedOutside)
return;
if (item.className === 'your-element-class')
clickedOutside = false;
});
if (clickedOutside)
// Make an action if it's clicked outside..
});
I hope this answer will help you ! (Let me know if my solution is not a good solution or if you see something to improve.)
我希望这个答案能帮到你!(如果我的解决方案不是一个好的解决方案,或者您认为有什么需要改进的地方,请告诉我。)

