JS事件冒泡:如何避免点击目标元素变化的问题?
问题:点击按钮子元素时无法获取父按钮的data属性
我给点赞、点踩按钮绑定了click事件,但点击按钮内的<span>区域时,ev.target指向的是子元素,拿不到父按钮上的data-item-id。试过ev.stopPropagation()没用,怎么解决?
解决方法
1. 用event.currentTarget替代event.target
currentTarget永远指向绑定事件监听器的元素(也就是你绑定点击事件的按钮),不管点击的是它的哪个子元素,直接用它就能拿到按钮上的data-item-id。
2. 通过closest()定位父按钮
如果需要从点击的子元素往上找到对应的按钮,可以用ev.target.closest('.comment-vote-up')(点赞按钮)或ev.target.closest('.comment-vote-down')(点踩按钮),这个方法会返回匹配选择器的最近祖先元素。
3. 事件委托(更简洁的批量处理方式)
把事件监听器绑定到父容器上,通过判断点击元素的祖先是否是目标按钮来处理,适合多个按钮的场景,减少重复绑定事件。
修改后的代码示例
方法1:使用currentTarget
const commentVotes = document.querySelectorAll('.comment-votes'); commentVotes.forEach((row) => { const up = row.querySelector('.comment-vote-up'); const down = row.querySelector('.comment-vote-down'); up.addEventListener('click', async (ev) => { const id = ev.currentTarget.getAttribute('data-item-id'); console.log({"target": ev.currentTarget, "ID": id}) }); down.addEventListener('click', async (ev) => { const id = ev.currentTarget.getAttribute('data-item-id'); console.log({"target": ev.currentTarget, "ID": id}) }) });
方法2:使用closest()
const commentVotes = document.querySelectorAll('.comment-votes'); commentVotes.forEach((row) => { const up = row.querySelector('.comment-vote-up'); const down = row.querySelector('.comment-vote-down'); up.addEventListener('click', async (ev) => { const button = ev.target.closest('.comment-vote-up'); const id = button.getAttribute('data-item-id'); console.log({"target": button, "ID": id}) }); down.addEventListener('click', async (ev) => { const button = ev.target.closest('.comment-vote-down'); const id = button.getAttribute('data-item-id'); console.log({"target": button, "ID": id}) }) });
方法3:事件委托
document.querySelector('.comment-votes').addEventListener('click', async (ev) => { const upButton = ev.target.closest('.comment-vote-up'); const downButton = ev.target.closest('.comment-vote-down'); if (upButton) { const id = upButton.getAttribute('data-item-id'); console.log({"action": "like", "ID": id}); } else if (downButton) { const id = downButton.getAttribute('data-item-id'); console.log({"action": "dislike", "ID": id}); } });
原HTML结构
<div class="comment"> <div class="comment-vote-box comment-votes mt-10"> <div class="vote-up"> <button class="comment-vote-up" data-item-id="11"> <span class="spacer">Like</span> <span>0</span> </button> </div> <div class="vote-down"> <button class="comment-vote-down" data-item-id="12"> <span class="spacer">Dislike</span> <span>1</span> </button> </div> </div> </div><!-- comment -->
原CSS样式
.comment .comment-vote-box { display: flex; gap: 10px; justify-content: flex-end; } .spacer { margin-right:10px; }
内容的提问来源于stack exchange,提问作者Max Pattern
相关产品推荐
相关产品推荐

