简体   繁体   中英

JS - Child element to not listen to delegated event

In the following snippet you will see a delegated event attached to document .

The key thing to note is:

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> 

As you can see, if you click on the "red-bordered span" it will not work, but if you click on the div it works. I know the reason for this and the "solution" is:

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

This; however, does not fully work, and causes this (click on both the span and then the 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> 

There are various other methods I have tested, including:

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');
}

But they all do not do what I want, which is: when you click anywhere in the div , it will toggle the active class

I think the solution lies somewhere event bubbling, but I have not been able to find a way to utilize this. Is there a way for child events to "ignore" event handlers on (non-)delegated events?

A jsfiddle for this can be found here .

PS I know another way to do this is:

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

and all the other variations, etc. but that runs into the same problem that I list above.

I think the solution lies somewhere event bubbling, but I have not been able to find a way to utilize this. Is there a way for child events to "ignore" event handlers on (non-)delegated events?

Yes event bubbling is part of the solution, and utilizing the properties of event.target and event.currentTarget will help you isolate a specific element along the event chain.

SNIPPET

 // 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 | (ie the element that was clicked on) and not | all of the other elements that happen to be on the | event chain (ie 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> 

You can use pointer-events :

The CSS property pointer-events allows authors to control under what circumstances (if any) a particular graphic element can become the target of mouse 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> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM