【问题标题】:JavaScript events and bubblingJavaScript 事件和冒泡
【发布时间】:2015-04-28 19:27:00
【问题描述】:

我有以下(简化的)标记代码:

<div id="container">
    <div data-value="1">
        <span>Click me 1</span>
    </div>
    <div data-value="2">
        <span>Click me 2</span>
    </div>
</div>
<div id="messages"></div>

我想通过仅在#container 上附加一个事件侦听器来利用冒泡,并获取点击的孩子的data-value。

document.getElementById('container').addEventListener('click', function(e){
    document.getElementById('messages').innerHTML = 'you clicked ' + e.target.dataset.value;
}, false);

如果点击区域是div 区域(小提琴中的红色区域),一切正常。当单击来自具有数据值的 div 的子项(例如单击蓝色跨度)而不更改事件侦听器时,如何获得 data-value?

这是小提琴:http://jsfiddle.net/hgLagy31/1/

【问题讨论】:

  • e.target.parentNode.dataset.value; - 如果你点击跨度。
  • 对,但这只是一个例子,带有数据值的 div 内的标记结构可能会改变 - 也有更多(大)子代

标签: javascript dom-events event-bubbling


【解决方案1】:

e.target 是用户单击的元素,它显示undefined,因为&lt;span&gt; 没有data-value 属性。您可以上树并找到最近的包含data-value 的祖先。

document.getElementById('container').addEventListener('click', function(e) {
  // Find nearest ancestor with data-value defined
  var node = e.target;
  while (!node.dataset.value) {
    node = node.parentNode;
  }
  document.getElementById('messages').innerHTML =
    'you clicked ' + node.dataset.value;
}, false);
#container > div {
  background: red;
}
#container > div > span {
  background: blue;
  color: white;
}
<div id="container">
  <div data-value="1">
    <span>Click me 1</span>
  </div>
  <div data-value="2">
    <span>Click me 2</span>
  </div>
</div>
<div id="messages"></div>

为了使其更加健壮,您可以在继续 while 循环之前检查 node 是否为 undefined,如果是则退出:

while (!node.dataset || !node.dataset.value) {
  node = node.parentNode;
  if (!node) {
    document.getElementById('messages').innerHTML =
        'Could not find data-value';
    return;
  }
}

document.getElementById('container').addEventListener('click', function(e) {
  // Find nearest ancestor with data-value defined
  var node = e.target;
  while (!node.dataset || !node.dataset.value) {
    node = node.parentNode;
    if (!node) {
      document.getElementById('messages').innerHTML = 'Could not find data-value';
      return;
    }
  }
  document.getElementById('messages').innerHTML =
    'you clicked ' + node.dataset.value;
}, false);
#container > div {
  background: red;
}
#container > div > span {
  background: blue;
  color: white;
}
<div id="container">
  <div data-value="1">
    <span>Click me 1</span>
  </div>
  <div data-value="2">
    <span>Click me 2</span>
  </div>
  <div>
    <span>Click me 3</span>
  </div>
</div>
<div id="messages"></div>

【讨论】:

    【解决方案2】:

    正如您要求的不涉及更改事件侦听器的解决方案...

    #container > div > span {
        background: blue;
        color: white;
        pointer-events: none;
    }
    

    这会让点击事件直接冒泡到容器中。

    【讨论】:

    • 不知道这个属性,谢谢。无论如何,正如在 cmets 中所说,标记可能会改变,我更喜欢一个允许我在不编辑 css 的情况下更改它的解决方案
    【解决方案3】:

    正如其他人提到的那样,获取目标元素,然后遍历.parentNode

    并不是所有的浏览器都支持target/toElement,所以我在获取目标元素的时候使用了如下的polyfill:

    var target = e.toElement || e.relatedTarget || e.target || function () { throw "Failed to attach an event target!"; }
    

    其中 e 是事件

    【讨论】:

    • 哪个浏览器使用toElement?我只知道srcElement 和target。哪个浏览器将relatedTarget 用于target?
    猜你喜欢
    • 2011-08-23
    • 2015-08-12
    • 1970-01-01
    • 1970-01-01
    • 2012-02-09
    • 2011-06-11
    • 2012-01-01
    • 1970-01-01
    相关资源
    最近更新 更多