You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 16:55:25