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.
// 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.