css 如果绑定目标是嵌套的,则事件委托不起作用

wi3ka0sx  于 2023-01-22  发布在  其他
关注(0)|答案(3)|浏览(108)

在Stackoverflow的同事(mplungjan,Michel)的建议下,我使用了eventdelegation模式作为评论列表,它运行良好,我对这个模式非常感兴趣,但是正如我已经怀疑的,如果绑定元素(button)包含两个子元素(span, span),就会出现问题。
因为我想从子元素的父元素中的target获取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>
qyswt5oh

qyswt5oh1#

问题在于,您使用.parentNode.parentNode来获取data-comment-id元素,但是当目标嵌套在其他<span>元素中时,父元素的数量会发生变化。
不要硬编码嵌套层,使用.closest()查找包含的控制器节点。

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

gwbalxhn2#

基于我在the other question中的上一条评论
const tgtButtonWhenSpansInsideButton = e.target.closest("button")
1.缓存对象
1.最接近的方法将获取按钮本身,即使没有子按钮
1.确保从要调用按钮的元素的包含元素中获取类

const commentList = document.querySelector('.comment-list');
const getObjectId = (tgt) => tgt.closest('.controller').dataset.commentId;

commentList.addEventListener('click', (ev) => {
  const tgt = ev.target.closest("button")
  const objectId = getObjectId(tgt);
  if (!objectId) return;
  console.log(objectId,"clicked")
  if (tgt.classList.contains('delete')) {
    console.log('2. Delete action');
    console.log('3. for relatedID', objectId);
  }

  if (tgt.classList.contains('edit')) {
    console.log('2. Edit action');
    console.log('3. for relatedID', objectId);
  }

  if (tgt.classList.contains('flag')) {
    console.log('2. Flag action');
    console.log('3. for relatedID', objectId);
  }

});
.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>
xmjla07d

xmjla07d3#

在本例中,如果单击的不是按钮,我将向上"遍历" DOM,如下所示

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

commentList.addEventListener('click', (ev) => {
  console.log('1. clicked', ev.target.tagName);

  let target = ev.target
  if (target.tagName === "SPAN") {
    target = target.parentElement
  }

  const commentId = target.parentElement.parentElement.getAttribute('data-comment-id');
  
  if (!commentId) return false;

  if (target.classList.contains('delete')) {
    console.log('2. Delete action');
    console.log('3. for relatedID', commentId);
  }
  
  if (target.classList.contains('edit')) {
    console.log('2. Edit action');
    console.log('3. for relatedID', commentId);
  }  
  
  if (target.classList.contains('flag')) {
    console.log('2. Flag action');
    console.log('3. for relatedID', commentId);
  }    
  
});
.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>

相关问题