检测点击外部元素(vanilla JavaScript)

Tib*_*tan 67 javascript

我到处搜索了一个很好的解决方案,但我找不到一个不使用jQuery的解决方案.

是否存在跨浏览器,正常方式(没有奇怪的黑客或容易破解代码),检测元素外部的点击(可能有孩子也可能没有孩子)?

fre*_*nte 131

添加一个事件侦听器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
  }
});
Run Code Online (Sandbox Code Playgroud)

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')
  }
});
Run Code Online (Sandbox Code Playgroud)
div {
  margin: auto;
  padding: 1em;
  max-width: 6em;
  background: rgba(0, 0, 0, .2);
  text-align: center;
}
Run Code Online (Sandbox Code Playgroud)
Is the click inside A or outside?
<div id="a">A
  <div id="b">B
    <div id="c">C</div>
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)

  • 似乎是我最优雅的解决方案. (10认同)
  • 这是我见过的最好的解决方案。 (4认同)

met*_*ngs 25

您需要在文档级别处理click事件.在事件对象中,您有一个target属性,即单击的最内层DOM元素.通过这种方式,您可以检查自己并将其父项向上走,直到文档元素,如果其中一个是您的监视元素.

请参阅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";
});
Run Code Online (Sandbox Code Playgroud)

与往常一样,由于addEventListener/attachEvent,这不是交叉浏览器兼容,但它的工作方式与此类似.

点击一个孩子,当不是event.target时,但其中一个父母是被监视的元素(我只是为此计算水平).如果找到元素,您也可以使用布尔变量,以便不从for子句内返回处理程序.我的例子是限制处理程序只在没有匹配时完成.

添加跨浏览器兼容性,我通常这样做:

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);
  }
};
Run Code Online (Sandbox Code Playgroud)

这是跨浏览器兼容的代码,用于将事件监听器/处理程序(包括thisIE中的重写)附加为元素,就像jQuery为其事件处理程序所做的那样.有很多论点要考虑一些jQuery;)

  • 如果用户单击元素的子元素,该怎么办? (4认同)
  • 使用此解决方案,您可以检查`target`属性(如元数所示,将是最内层的DOM元素) - 及其所有父元素.要么到达您观看的元素,这意味着用户在其中单击,或者您到达文档元素,在这种情况下,他/她在外面单击.或者,你可以添加两个点击监听器 - 一个在文档元素上,另一个在监视元素上,它使用`event.stopPropagation()`/ cancelBubble`,这样文档元素上的监听器只能通过外部点击触发观看的元素. (3认同)
  • 这是'for`的一些巧妙使用.出于好奇,是否有任何理由不将变量中的元素与事件上的目标进行比较(使用严格比较)? (2认同)

Akh*_*ran 7

这个怎么样:

jsBin演示

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');
} 
Run Code Online (Sandbox Code Playgroud)