2017-09-25 110 views
0

https://jsfiddle.net/y444stqv/3/包括上动态创建的元素

怎样包括父项的所有子元素“单击”事件监听器上点击事件侦听器的子元素?例如,我动态创建以下html:

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

我想要将点击处理程序绑定到每个“item”div。因此,如果您单击任何“item”(即子节点“h3”或“p”标记)节点的子元素,我仍然想执行“handleClick”单击处理程序。但是,当你点击ID“donotexecuteclicklistener”,我不希望这个点击处理程序触发。

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

“*我想使用事件委托绑定一个单击处理... *”你是滥用表达“*事件委托*”,这是有关捕获冒泡事件,而不是听众。请在这里发布可运行代码,而不是其他地方。 – RobG

回答

0

要充分利用事件委派的概念,请将单个侦听器附加到内容元素上,然后查看事件来自哪里以确定响应。

如果它来自div中的元素,请执行任何操作

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>

另见Element.closest。您也可以考虑更通用的“通过选择器获得父母”,但是表现可能更慢,例如,

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

并通过调用它:

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

这是默认情况下发生的!当一个元素被触发时,它会被“冒泡”到父元素。您可以看到click事件冒泡Event.bubbles属性(https://developer.mozilla.org/en-US/docs/Web/API/Event/bubbles)。

元素动态生成的事实不会影响此行为:事件仍然会在动态生成的元素上冒泡。

为了获得事件发生的元素,您可以使用e.target

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

务必小心:e.stopPropagation()方法取消该起泡功能,所以你需要确保你在任何地方调用它。如果你无法让事件冒泡,这可能是罪魁祸首。