【问题标题】:Event delegation does not work if the bound target is nested如果绑定目标是嵌套的,则事件委托不起作用
【发布时间】:2023-01-19 21:41:39
【问题描述】:

对于评论列表,我使用事件委托模式经过 * 同事的推荐(mplungjan, 米歇尔).它运作良好,我对这种模式非常感兴趣。但是正如我已经怀疑的那样,如果绑定元素(按钮)包含两个子元素(span, span),则会出现问题。

由于我想从子元素的父元素中的目标获取 CommentID,因此它仅适用于您在按钮内的跨度之间精确单击的情况。实际上是 currentTarget 的情况,但在这种情况下不起作用,因为点击的元素是整个评论列表。

问题:我该怎么做才能修复它?

const commentList = document.querySelector('.comment-list');

commentList.addEventListener('click', (ev) => {
  console.log('1. clicked');
  const getObjectId = () => {
    return ev.target.parentNode.parentNode.getAttribute('data-comment-id');
  }
  
  if (! getObjectId()) return false;

  if (ev.target.classList.contains('delete')) {
    console.log('2. Delete action');
    console.log('3. for relatedID', getObjectId());
  }
  
  if (ev.target.classList.contains('edit')) {
    console.log('2. Edit action');
    console.log('3. for relatedID', getObjectId());
  }  
  
  if (ev.target.classList.contains('flag')) {
    console.log('2. Flag action');
    console.log('3. for relatedID', getObjectId());
  }    
  
});
.controller {
  display: flex;
  gap:20px;
}
.comment {
  margin-bottom: 20px;
  background: gray;
}

.controller button > span {
  background: orange;
}

.controller button span:first-child {
  margin-right: 10px;
}
<div class="comment-list">
  <div class="comment">
    <div class="content">lorem 1. Dont work! Nested button.</div>
    <div class="controller" data-comment-id="1">
      <div class="delete">
        <button class="delete"><span>delete</span><span>ICON</span></button>        
      </div>
      <div class="edit">
        <button class="edit"><span>edit</span><span>ICON</span></button>
      </div>
      <div class="flag">
        <button class="flag"><span>flag</span><span>ICON</span></button>          
      </div>
    </div>
  </div>
  
  <div class="comment">
    <div class="content">lorem 2. Work! </div>
    <div class="controller" data-comment-id="2">
      <div class="delete"><button class="delete">delete</button></div>
      <div class="edit"><button class="edit">edit</button></div>
      <div class="flag"><button class="flag">flag</button></div>
    </div>
  </div>
  
  <div class="comment">
    <div class="content">lorem 3. Work! </div>
    <div class="controller" data-comment-id="3">
      <div class="delete"><button class="delete">delete</button></div>
      <div class="edit"><button class="edit">edit</button></div>
      <div class="flag"><button class="flag">flag</button></div>
    </div>
  </div>  
  
</div>

【问题讨论】:

    标签: javascript html css


    【解决方案1】:

    问题是您使用.parentNode.parentNode 获取带有data-comment-id 的元素,但是当目标嵌套在其他&lt;span&gt; 元素中时,父元素的数量会发生变化。

    不要对嵌套级别进行硬编码,使用 .closest() 查找包含的控制器节点。

      const getObjectId = () => {
        return ev.target.closest('.controller').getAttribute('data-comment-id');
      }
    

    【讨论】: