JS - 不听取委托事件的子元素

时间:2016-09-07 02:14:14

标签: javascript html css

在以下代码段中,您会看到附加到document的委托事件。

需要注意的关键是:

if (e.target.parentNode.id === 'put-stuff-here') {
  e.target.classList.toggle('active');
}

function loadItems(target) {
  for (var i = 0; i < 10; i++) {
    setTimeout(function() {
      target.insertAdjacentHTML('beforeend', '<div class="new"><span>Click me!</span>Or click me!</div>');
    }, (i * 250));
  }
}

document.getElementsByTagName('button')[0].addEventListener('click', function(e) {
  loadItems(document.getElementById('put-stuff-here'));
});

document.addEventListener('click', function(e) {
  if (e.target.parentNode.id === 'put-stuff-here') {
    e.target.classList.toggle('active');
  }
});
body {
  font-family: 'arial';
  display: flex;
  flex-flow: column;
}
body > * {
  margin-bottom: 16px;
}
#put-stuff-here:before {
  display: block;
  padding: 8px;
  text-align: center;
  content: 'Target Location:';
  background-color: PapayaWhip;
}
#put-stuff-here {
  border: 1px solid black;
}
.new {
  background-color: SteelBlue;
  padding: 8px;
}
.new span {
  border: 1px dotted red;
  margin: 8px;
}
.active {
  background-color: white;
}
<button>Press Me!</button>
<div id="put-stuff-here">

</div>

正如您所看到的,如果您单击“红边跨度”它将无法工作,但如果您单击div它可以工作。我知道这个的原因和“解决方案”是:

if (e.target.parentNode.id === 'put-stuff-here' || e.target.parentNode.parentNode.id === 'put-stuff-here') {
  e.target.classList.toggle('active');
}

此;但是,没有完全工作,并导致这个(点击跨度然后点击div):

function loadItems(target) {
  for (var i = 0; i < 10; i++) {
    setTimeout(function() {
      target.insertAdjacentHTML('beforeend', '<div class="new"><span>New!</span></div>');
    }, (i * 250));
  }
}

document.getElementsByTagName('button')[0].addEventListener('click', function(e) {
  loadItems(document.getElementById('put-stuff-here'));
});

document.addEventListener('click', function(e) {
  if (e.target.parentNode.id === 'put-stuff-here' || e.target.parentNode.parentNode.id === 'put-stuff-here') {
    e.target.classList.toggle('active');
  }
});
body {
  font-family: 'arial';
  display: flex;
  flex-flow: column;
}
body > * {
  margin-bottom: 16px;
}
#put-stuff-here:before {
  display: block;
  padding: 8px;
  text-align: center;
  content: 'Target Location:';
  background-color: PapayaWhip;
}
#put-stuff-here {
  border: 1px solid black;
}
.new {
  background-color: SteelBlue;
  padding: 8px;
}
.new span {
  border: 1px dotted red;
  margin: 8px;
}
.active {
  background-color: white;
}
<button>Press Me!</button>
<div id="put-stuff-here">

</div>

我测试过各种其他方法,包括:

if (e.target.parentNode.id === 'put-stuff-here' || e.target.parentNode.parentNode.id === 'put-stuff-here') {
  e.target.classList.toggle('active') || e.target.parentNode.classList.toggle('active');
}

但是他们都没有做我想做的事情,那就是:当您点击div中的 时,它会切换active

  

我认为解决方案存在于事件冒泡的地方,但我无法找到利用它的方法。有没有办法让子事件“忽略”(非)委托事件的事件处理程序?

可以找到一个jsfiddle here

P.S。我知道另一种方法是:

if (e.target.classList.contains('new') || e.target.parentNode.classList.contains('new')) {
  e.target.classList.toggle('active');
}

以及所有其他变体等,但遇到了我在上面列出的相同问题。

2 个答案:

答案 0 :(得分:1)

  

我认为解决方案存在于事件冒泡的地方,但我无法找到利用它的方法。有没有办法让子事件“忽略”(非)委托事件的事件处理程序?

是事件冒泡是解决方案的一部分,利用event.targetevent.currentTarget的属性将帮助您隔离事件链中的特定元素。

// Reference the parent element
var parent = document.getElementById('parent');

// add an eventListener to the parent element
parent.addEventListener('click', function(event) {

  /*
  | While in bubbling phase, we only want event.target
  | (i.e. the element that was clicked on) and not
  | all of the other elements that happen to be on the
  | event chain (i.e. event.currentTarget)
  */

  if (event.target !== event.currentTarget) {

    // Store the event.target in a var
    var tgt = event.target;

    // Do whatever you want to event.target
    tgt.classList.toggle('active');
  }
  /*
  | Stop any further bubbling so that event.target is
  | the only element on the event chain that reacts to
  | the click event.
  */
  event.stopPropagation();
}, false);
#parent {
  background: rgba(0, 0, 0, .75);
  border: 3px dashed red;
  padding: 10px;
}
.child {
  background: rgba(255, 255, 255, .75);
  border: 1px solid blue;
  margin: 5px;
  height: 15px;
}
.active {
  background: red;
  outline: 2px dotted orange;
}
<main id='parent'>
  <section class='child'></section>
  <section class='child'></section>
  <section class='child'></section>
  <section class='child'></section>
  <section class='child'></section>
  <section class='child'></section>
  <section class='child'></section>
  <section class='child'></section>
  <section class='child'></section>
  <section class='child'></section>
</main>

答案 1 :(得分:1)

您可以使用pointer-events

  

CSS属性pointer-events允许作者控制什么   情况(如果有的话)特定的图形元素可以成为   鼠标事件的目标。

.new > * {
  pointer-events: none;
}

&#13;
&#13;
function loadItems(target) {
  for (var i = 0; i < 10; i++) {
    setTimeout(function() {
      target.insertAdjacentHTML('beforeend', '<div class="new"><span>Click me!</span>Or click me!</div>');
    }, (i * 250));
  }
}

document.getElementsByTagName('button')[0].addEventListener('click', function(e) {
  loadItems(document.getElementById('put-stuff-here'));
});

document.addEventListener('click', function(e) {
  if (e.target.parentNode.id === 'put-stuff-here') {
    e.target.classList.toggle('active');
  }
});
&#13;
body {
  font-family: 'arial';
  display: flex;
  flex-flow: column;
}
body > * {
  margin-bottom: 16px;
}
#put-stuff-here:before {
  display: block;
  padding: 8px;
  text-align: center;
  content: 'Target Location:';
  background-color: PapayaWhip;
}
#put-stuff-here {
  border: 1px solid black;
}
.new {
  background-color: SteelBlue;
  padding: 8px;
}
.new > span {
  border: 1px dotted red;
  margin: 8px;
  pointer-events: none;
}
.active {
  background-color: white;
}
&#13;
<button>Press Me!</button>
<div id="put-stuff-here">

</div>
&#13;
&#13;
&#13;