只听取div中的点击而不干扰其子节目(一个hitbox)?

时间:2017-04-03 12:41:00

标签: javascript html css events elm

我有以下DOM结构:

#container {
  position: absolute;
  width: 100px;
  height: 100px;
  background-color: blue;
}

#content {
  position: absolute;
  width: 90%;
  height: 90%;
  background-color: yellow;
}

#content_child {
  position: absolute;
  width: 30px;
  height: 30px;
  left: 150px;
  top: 150px;
  background-color: red;
}
<div id="container">
  <div id="content">
    <div id="content_text">Hello</div>
    <div id="content_child"></div>
  </div>
</div>

#content_text#content_child会有各种鼠标事件。我想在#container上检测鼠标事件。但是,如果我只是将事件附加到#container,它们将被其子项激活,这是不可取的。我的要求如下(我使用点击事件作为例子):

  • 点击#container时,我希望其事件触发
  • 当一个孩子以图形方式位于 其div(如#content_text)时,我会同时想要孩子和#container的事件触发
  • 当一个孩子以图形方式位于时,点击其div(如#content_child),我只想 该孩子的事件触发

我事先知道哪些孩子会在div之外和之内。

我可以想到两种方法,都存在很大缺陷:

  1. 将鼠标事件附加到#container,并且对于div之外的每个子项,添加与附加到#container的事件相同的事件,但使处理程序不做任何事情并使它们不传播。这有点笨拙。
  2. 添加“点击区域”/“hitbox”div ... 某处。这将是一个透明的div,它是#container(并且大小相同)的孩子,它会记录点击,这不会传播给它的兄弟姐妹的孩子,即#content的孩子,因为他们是兄弟姐妹。如果我将它放在#content之前,所有hitbox的事件都会被#content吃掉而且它们不会触发。如果我把它放在后面,那就是相同的问题。我不能同时在同一个地方同时听同样的事件,也不能把它们传给所有的孩子。
  3. 有没有办法实现一个hitbox行为没有重大的重组或花哨的Javascript(我使用榆木,所以两者都不是一个选项)?

3 个答案:

答案 0 :(得分:2)

将处理程序附加到#container。当您收到该事件时,如果它通过容器外的图形的子项,则忽略它。

您可以通过检查事件对象上的target和(如果需要)parentNode等来确定点击进入容器的路径,直到您到达容器。< / p>

这是一个例子(在这里,我硬编码检查孩子是否在父母内部以图形方式,因为你说你已经知道了;不需要进入工作通过一个简单的例子来解决这个问题):

&#13;
&#13;
function hook(selector, event, handler) {
  var elements = document.querySelectorAll(selector);
  Array.prototype.forEach.call(elements, function(el) {
    el.addEventListener(event, handler, false);
  });
}
// container's click handler
hook("#container", "click", function(e) {
  if (passedThroughChildOutsideBox(e, this)) {
    // Ignore
  } else {
    console.log("container click");
  }
});
// child handlers
hook("#content_text, #content_child", "click", function(e) {
  console.log(this.id + " click");
});

// Fake detection
function passedThroughChildOutsideBox(e, container) {
  var node = e.target;
  while (node && node !== container) {
    if (node.id === "content_child") { // Again, just hardcoded for demo
      return true;
    }
    node = node.parentNode;
  }
  return false;
}
&#13;
#container {
  position: absolute;
  width: 100px;
  height: 100px;
  background-color: blue;
}

#content {
  position: absolute;
  width: 90%;
  height: 90%;
  background-color: yellow;
}

#content_child {
  position: absolute;
  width: 30px;
  height: 30px;
  left: 150px;
  top: 150px;
  background-color: red;
}
&#13;
<div id="container">
  <div id="content">
    <div id="content_text">Hello</div>
    <div id="content_child"></div>
  </div>
</div>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

使用停止传播https://developer.mozilla.org/en/docs/Web/API/Event/stopPropagation

将阻止进一步传播..

var container = document.getElementById("container");
var container_text = document.getElementById("content_text");
var container_child = document.getElementById("content_child");

container.addEventListener("click", function () {
    console.log('this is the container');
});

container_text.addEventListener("click", function () {
    console.log('this is the container_text');
});
container_child.addEventListener("click", function (event) {
  event.stopPropagation();
    console.log('this is the container_child');
});
#container {
  position: absolute;
  width: 100px;
  height: 100px;
  background-color: blue;
}

#content {
  position: absolute;
  width: 90%;
  height: 90%;
  background-color: yellow;
}

#content_child {
  position: absolute;
  width: 30px;
  height: 30px;
  left: 150px;
  top: 150px;
  background-color: red;
}
<div id="container">
  <div id="content">
    <div id="content_text">Hello</div>
    <div id="content_child"></div>
  </div>
</div>

答案 2 :(得分:0)

尝试e.stopPropagation()会阻止父母点击查找子事件。

&#13;
&#13;
#container {
  position: absolute;
  width: 100px;
  height: 100px;
  background-color: blue;
}

#content {
  position: absolute;
  width: 90%;
  height: 90%;
  background-color: yellow;
}

#content_text {
  background: grey;
}

#content_child {
  position: absolute;
  width: 30px;
  height: 30px;
  left: 150px;
  top: 150px;
  background-color: red;
  color: #fff;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
  <div id="content">
    <div id="content_text">Hello</div>
    <div id="content_child">hi</div>
  </div>
</div>
&#13;
{{1}}
&#13;
&#13;
&#13;

https://codepen.io/anon/pen/zZbYvp

// codepen.io/anon/pen/zZbYvp