2017-09-25 3 views
0

https://jsfiddle.net/y444stqv/3/Inclure des éléments enfants sur écouteur d'événements, cliquez sur les éléments créés dynamiquement

Comment puis-je inclure tous les éléments de l'enfant dans le parent écouteur d'événement « clic »? Par exemple, je crée dynamiquement le code HTML suivant:

<div id="content"> 
    <div id="donotexecuteclicklistener">But don't include me!</div> 
     <!-- Dynamically generated --> 
     <div class="items"> 
     <div class="item item-0"> 
      <h3>Item 0</h3> 
      <p>Some desc</p> 
     </div> 

     <div class="item item-1"> 
      <h3>Item 1</h3> 
      <p>Some desc</p> 
     </div> 

     <div class="item item-2"> 
      <h3>Item 2</h3> 
      <p>Some desc</p> 
     </div> 

     <div class="item item-3"> 
      <h3>Item 3</h3> 
      <p>Some desc</p> 
     </div> 
     </div> 
    </div> 

Je veux lier un gestionnaire de clic à chaque div « item ». Ainsi, si vous cliquez sur un élément qui est un enfant du nœud "item" (c'est-à-dire le nœud enfant "h3" ou "p"), je souhaite toujours exécuter le gestionnaire de clic "handleClick". MAIS, lorsque vous cliquez sur l'identifiant "donotexecuteclicklistener", je ne veux pas que ce gestionnaire de clic se déclenche.

var items = []; 
    var $content = document.getElementById('content'); 

    for (var i = 0; i < 4; i++) { 
    // using ES6 template literals for ease 
    var item = ` 
     <div class="item" id="item-${i}"> 
      <h3>Item ${i}</h3> 
      <p>Some desc about item ${i}</p> 
     </div> 
    `; 

    items.push(item); 
    } 

    var html = items.join(' '); 
    $content.innerHTML = html; 

    var handleClick = function(event) { 
     console.log('do something with item', this, event); 
    } 

    $content.addEventListener('click', function(event) { 
     console.log(event.target.id); 
     var elements = $content.querySelectorAll('.item'); 
     var hasMatch = Array.prototype.indexOf.call(elements, event.target) >= 0; 
     console.log(hasMatch); 

     if (hasMatch) { 
     handleClick.call(event.target, event); 
     } 
    }) 
+0

« * Je veux utiliser la délégation de l'événement pour lier un gestionnaire de clic ... * » vous vous détournez l'expression « * délégation de l'événement * », qui est sur la capture événements bouillonnants, ne pas attacher les auditeurs. S'il vous plaît, envoyez un code exécutable ici, pas ailleurs. – RobG

Répondre

0

Pour utiliser le concept de délégation d'événement à son plein potentiel, attachez un seul écouteur à l'élément contenu, puis consultez d'où proviennent les événements pour déterminer la réponse.

Si elle provient d'un élément à l'intérieur d'une div avec la classe item, faites ce que vous voulez, par ex.

function handleClick(e){ 
 
    var el = e.target; 
 
    var div = getParentByClass(el, 'item'); 
 
    if (div) { 
 
    console.log(div.className); 
 
    } else { 
 
    console.log('no item parent') 
 
    } 
 
} 
 

 
// Get self or first parent with particular class 
 
// May be replaced by Element.closest in future 
 
function getParentByClass(el, className) { 
 
    do { 
 
    if (el.classList.contains(className)) { 
 
     return el; 
 
    } else { 
 
     el = el.parentNode; 
 
    } 
 
    } while (el && el.parentNode) 
 
} 
 

 

 
window.onload = function(){ 
 
    document.getElementById('content').addEventListener('click', handleClick, false); 
 
} 
 
//*/
<div id="content"> 
 
    <div id="donotexecuteclicklistener">But don't include me!</div> 
 
     <!-- Dynamically generated --> 
 
     <div class="items"> 
 
     <div class="item item-0"> 
 
      <h3>Item 0</h3> 
 
      <p>Some desc</p> 
 
     </div> 
 

 
     <div class="item item-1"> 
 
      <h3>Item 1</h3> 
 
      <p>Some desc</p> 
 
     </div> 
 

 
     <div class="item item-2"> 
 
      <h3>Item 2</h3> 
 
      <p>Some desc</p> 
 
     </div> 
 

 
     <div class="item item-3"> 
 
      <h3>Item 3</h3> 
 
      <p>Some desc</p> 
 
     </div> 
 
     </div> 
 
    </div>

Voir aussi Element.closest. Vous pouvez également envisager un générique "get parent by selector", mais les performances peuvent être plus lentes, par ex.

function getParentBySelector(el, selector) { 
    var node; 
    var els = document.querySelectorAll(selector); 
    els = els && els.length? Array.from(els) : []; 

    while (el && el.parentNode) { 
    el = el.parentNode; 
    node = els.find(x => x === el); 
    if (node) return node; 
    } 
} 

et l'appeler par:

var div = getParentBySelector(el, 'div.item'); 
0

Cela se produit par défaut! Lorsqu'un élément est déclenché sur un enfant, il est "propagé" vers les éléments parents. Vous pouvez voir que l'événement click est barboté avec la propriété Event.bubbles (https://developer.mozilla.org/en-US/docs/Web/API/Event/bubbles).

Le fait que l'élément ait été généré de manière dynamique n'affecte pas ce comportement: les événements continueront de bulle sur les éléments générés dynamiquement. Pour obtenir l'élément auquel l'événement s'est produit, vous pouvez utiliser e.target.

ancestor.addEventListener('click', (e) => { 
    const element = e.target; 
}); 

Attention: la méthode e.stopPropagation() annule cette fonctionnalité de bouillonnement, de sorte que vous devez vous assurer que vous n'êtes pas appeler partout. Si vous avez des difficultés à faire exploser les événements, cela peut être le coupable.