如何为带事件参数与自定义参数的函数添加、移除事件监听器
核心问题原因
removeEventListener 必须和 addEventListener 传入完全相同的回调函数引用才能匹配成功,你之前直接传入匿名函数作为回调,每次调用绑定方法都会生成新的函数引用,自然无法找到对应回调完成移除。
推荐实现方案
方案1:用WeakMap存储回调引用(兼容性好)
用WeakMap存储每个元素对应的回调实例,元素销毁时可自动回收引用,不会造成内存泄漏,同时支持同时给多个元素绑定监听:
// 存储元素与对应监听回调的映射关系 const listenerMap = new WeakMap<HTMLElement, (e: MouseEvent) => void>(); const listener = (element: HTMLElement, e: MouseEvent): void => { if (e.target instanceof Element && element && !element.contains(e.target)) { element.style.backgroundColor = 'red'; } } function addEventListener (element: HTMLElement) { // 避免重复绑定 if (listenerMap.has(element)) return; const callback = (e: MouseEvent) => listener(element, e); listenerMap.set(element, callback); document.addEventListener('mouseup', callback); } function removeEventListener (element: HTMLElement) { const callback = listenerMap.get(element); if (!callback) return; document.removeEventListener('mouseup', callback); listenerMap.delete(element); }
方案2:用AbortController(写法更简洁)
现代浏览器支持的AbortController可以直接中断监听,不需要手动匹配回调引用:
const listener = (element: HTMLElement, e: MouseEvent): void => { if (e.target instanceof Element && element && !element.contains(e.target)) { element.style.backgroundColor = 'red'; } } // 存储元素与对应AbortController实例的映射关系 const controllerMap = new WeakMap<HTMLElement, AbortController>(); function addEventListener (element: HTMLElement) { if (controllerMap.has(element)) return; const controller = new AbortController(); controllerMap.set(element, controller); document.addEventListener('mouseup', (e) => listener(element, e), { signal: controller.signal }); } function removeEventListener (element: HTMLElement) { const controller = controllerMap.get(element); if (!controller) return; // 调用abort即可直接移除对应监听 controller.abort(); controllerMap.delete(element); }
关于bind写法的补充
你之前尝试bind时不需要提前绑定MouseEvent参数,bind预传的参数会排在事件触发参数的前面,自动传入原函数,单元素绑定场景下可以直接这么写:
let callback: ((e: MouseEvent) => void) | null = null; function addEventListener (element: HTMLElement) { // 只需要预传element,MouseEvent会自动作为第二个参数传入listener callback = listener.bind(null, element); document.addEventListener('mouseup', callback); } function removeEventListener () { if (!callback) return; document.removeEventListener('mouseup', callback); callback = null; }
内容的提问来源于stack exchange,提问作者ibocon
相关产品推荐
相关产品推荐

