如何为带参数的函数正确使用removeEventListener?
解决类中带参数事件监听器的移除问题
问题原因
你当前代码移除监听器失败的核心原因:
- 添加监听器时用了匿名箭头函数
(elem) => this.selectElement(elem, i),每次循环都会生成全新的函数实例,和this.selectElement不是同一个引用,removeEventListener找不到对应函数,自然无法移除。 - 另外,
selectElement是类的箭头函数属性,本身已经绑定了this,构造函数里的this.selectElement = this.selectElement.bind(this)属于多余操作,可以直接删除。
解决方案
方案一:用bind绑定参数并保存函数引用
通过bind生成绑定了参数的函数实例,把这个实例存到元素的自定义属性中,移除时直接调用这个实例即可:
export default class Quiz { constructor() { this.eventHandlers(); } eventHandlers = () => { const listItem = document.querySelectorAll('.answer-menu__item'); listItem.forEach((elem, index) => { // 用bind绑定this和index参数,生成固定的函数实例 const clickHandler = this.selectElement.bind(this, index); elem.addEventListener('click', clickHandler); // 将函数实例存到元素的dataset中,方便后续移除 elem.dataset.handler = clickHandler; }); } selectElement = (index, event) => { const target = event.currentTarget; // 取出之前存储的函数实例 const handler = target.dataset.handler; // 移除监听器 target.removeEventListener('click', handler); // 清理存储的函数引用 delete target.dataset.handler; // 这里写你的业务逻辑 console.log(`选中索引为${index}的选项`); } }
注意:bind绑定参数的顺序是先this,再自定义参数,所以事件触发时,第一个参数是绑定的index,第二个是原生事件对象event。
方案二:通过DOM结构获取索引(无需绑定参数)
如果所有.answer-menu__item都有同一个父元素,可以直接通过元素在父节点中的位置获取索引,避免绑定参数带来的函数引用问题:
export default class Quiz { constructor() { this.eventHandlers(); } eventHandlers = () => { const listItem = document.querySelectorAll('.answer-menu__item'); listItem.forEach(elem => { // 直接绑定原函数,无需包裹匿名函数 elem.addEventListener('click', this.selectElement); }); } selectElement = (event) => { const target = event.currentTarget; const parent = target.parentElement; // 将父元素的子节点转为数组,获取当前元素的索引 const index = Array.from(parent.children).indexOf(target); // 直接移除监听器,因为用的是同一个函数引用 target.removeEventListener('click', this.selectElement); // 这里写你的业务逻辑 console.log(`选中索引为${index}的选项`); } }
这种方式代码更简洁,也不需要额外存储函数引用,适合DOM结构固定的场景。
内容的提问来源于stack exchange,提问作者wowblvck
相关产品推荐
相关产品推荐

