addEventListener事件未按预期冒泡?如何实现子元素触发父元素监听
事件冒泡与事件委托的误区解决
我对JavaScript中的事件冒泡概念存在理解误区。现有如下代码:
addGlobalEventListener("click", ".green", (e) => { console.log("clicked green"); }); function addGlobalEventListener(type, selector, callback) { document.addEventListener(type, (e) => { if (e.target.matches(selector)) { callback(e); } }); }
.red { width: 50px; height: 50px; background-color: red } .green { width: 150px; height: 150px; background-color: green } .blue { width: 300px; height: 300px; background-color: blue }
<div class="blue"> <div class="green"> <div class="red"> </div> </div> </div>
我原本认为,点击.red盒子或.green盒子时,控制台都会打印"clicked green",点击.blue盒子则不会——因为点击.red时事件会向上冒泡经过.green父元素。但实际只有点击.green盒子时才生效。请问如何修改代码,让点击.red或.green类的div时,控制台都输出"clicked green"?
问题原因
你当前的代码用e.target.matches(selector)判断,e.target指的是触发事件的最底层元素:点击.red时,e.target是.red元素,它不匹配.green选择器,所以回调不会执行。事件确实会冒泡,但你的判断逻辑没利用到冒泡的特性。
修改方案
把判断逻辑改成检查触发元素的DOM路径上是否存在匹配.green的元素,用Element.closest()方法即可实现:
addGlobalEventListener("click", ".green", (e) => { console.log("clicked green"); }); function addGlobalEventListener(type, selector, callback) { document.addEventListener(type, (e) => { // 从触发元素向上找第一个匹配选择器的元素(包括自身) const matchingEl = e.target.closest(selector); if (matchingEl) { // 可选:将回调的this绑定到匹配的元素,和直接绑定事件的行为一致 callback.call(matchingEl, e); } }); }
原理说明
closest(selector)会从当前元素开始,向上遍历DOM树,返回第一个匹配指定选择器的元素;如果找不到则返回null。- 点击.red时,
e.target.closest(".green")会找到它的父元素.green,条件成立,执行回调;点击.green时直接匹配自身,也会执行;点击.blue时找不到匹配元素,所以不触发。
内容的提问来源于stack exchange,提问作者learyjk
相关产品推荐
相关产品推荐

