如何使用removeEventListener选择移除后代元素的事件监听?
问题描述
我有数千个内部包含数百个后代元素的div,希望通过removeEventListener选择性移除部分后代元素的click事件监听。具体需求是指定div内哪些后代元素继续监听click事件,比如:
- 让input和textarea不再监听click事件,但div和p标签保持监听;
- 或者仅让textarea监听,其余元素都不监听。
原始代码示例
CSS
.frame { width: 300px; height: 300px; background-color: brown; } input { margin: auto; } p { font: bold 200% roboto; text-align: center; }
HTML
<body> <div class="frame"> <input placeholder=""> <textarea></textarea> <p>THIS IS P TAG</p> div area </div> <div class="frame"> <input placeholder=""> <textarea></textarea> <p>THIS IS P TAG</p> div area </div> </body>
原始JS
const labels = document.querySelectorAll('.frame'); for (var i = 0; i < labels.length; ++i) { labels[i].addEventListener('click', function touch() { // resize div if( this.clientWidth == 300) { this.style.width = "600px"; this.style.height = "600px"; }else{ this.style.width = "300px"; this.style.height = "300px"; }; //remove the event this.firstElementChild.removeEventListener('click', touch); //document.querySelectorAll('input').removeEventListener('click', touch); }); };
解决方案
首先要明确:你原始代码里的removeEventListener写法是无效的——事件是绑定在父级.frame上的,input、textarea这些后代元素根本没绑定过touch这个处理函数,它们触发事件只是因为事件冒泡特性。针对你这种大量元素的场景,更高效的方式是用事件委托+目标元素判断,不用挨个给后代加/删监听。
方式1:指定允许触发事件的元素类型
在父级.frame的click事件里,判断触发事件的目标元素是否属于你允许的类型,是就执行逻辑,否则直接跳过。
示例:仅允许div和p触发(input、textarea不触发)
const frames = document.querySelectorAll('.frame'); frames.forEach(frame => { frame.addEventListener('click', function(e) { const targetTag = e.target.tagName.toLowerCase(); // 定义允许触发的标签列表 const allowedTags = ['div', 'p']; // 不在允许列表里就直接返回,不执行后续逻辑 if (!allowedTags.includes(targetTag)) return; // 执行resize逻辑 this.style.width = this.clientWidth === 300 ? "600px" : "300px"; this.style.height = this.clientWidth === 300 ? "600px" : "300px"; }); });
示例:仅允许textarea触发(其余都不触发)
只需要修改allowedTags数组即可:
const allowedTags = ['textarea'];
方式2:如果必须用removeEventListener(不推荐大量元素场景)
如果某些场景下你必须给每个后代元素单独绑定事件再移除,那得先给所有目标元素绑定同一个处理函数,之后再按需移除:
// 先定义共用的事件处理函数 function handleClick(e) { const frame = e.target.closest('.frame'); frame.style.width = frame.clientWidth === 300 ? "600px" : "300px"; frame.style.height = frame.clientWidth === 300 ? "600px" : "300px"; } // 给所有后代元素绑定事件 const frames = document.querySelectorAll('.frame'); frames.forEach(frame => { const allChildren = frame.querySelectorAll('input, textarea, p, div'); allChildren.forEach(child => child.addEventListener('click', handleClick)); }); // 移除input和textarea的监听 document.querySelectorAll('input, textarea').forEach(el => { el.removeEventListener('click', handleClick); });
这种方式在元素数量极多的情况下性能很差,不建议使用。
内容的提问来源于stack exchange,提问作者Table
相关产品推荐
相关产品推荐

