JS -子元素不监听委托事件

JS - Child element to not listen to delegated event

本文关键字:事件 监听 元素 JS      更新时间:2023-09-26

在下面的代码片段中,您将看到一个委托事件附加到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>

正如你所看到的,如果你点击"红边span",它将不起作用,但如果你点击div,它就起作用了。我知道原因,解决办法是:

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

;但是,它不能完全工作,并导致以下情况(分别单击span和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

我认为解决方案在于某个地方事件冒泡,但我没能找到一种方法来利用这一点。是否有一种方法可以让子事件"忽略"(非)委托事件的事件处理程序?

可以在这里找到一个jsfile。

注:我知道另一种方法是:

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

和所有其他的变化,等等,但这会遇到我上面列出的同样的问题

您可以使用pointer-events:

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

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

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;
  pointer-events: none;
}
.active {
  background-color: white;
}
<button>Press Me!</button>
<div id="put-stuff-here">
</div>

我认为解决方案在于某个地方事件冒泡,但我没能找到一种方法来利用这一点。子事件是否有"忽略"的方法?(非)委托事件的事件处理程序?

是的,事件冒泡是解决方案的一部分,并且利用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>