forEach循环中添加的点击事件监听器触发多次的问题如何解决
问题原因
你遇到的点击事件触发3次的问题,核心是事件监听器被重复绑定了3次,常见触发场景如下:
- 虽然JS模块仅加载一次,但
lightbox()函数被重复执行了3次:动态导入只会加载模块代码一次,但导出的lightbox函数可以被多次调用,比如DOMContentLoaded事件被异常触发多次、其他业务逻辑重复调用了该函数等 - 你当前使用匿名函数作为事件回调,每次调用
addEventListener都会新增独立的监听器,不会覆盖之前绑定的同类型事件,调用3次就会每个元素绑定3个监听器,点击一次就触发3次
解决方案
推荐用事件委托的方案,从根源避免重复绑定问题,性能也更优:
修改后的lightbox.js代码
// 模块内加初始化标志位,防止重复执行 let isLightboxInit = false; export const lightbox = () => { if (isLightboxInit) return; const gallery = document.querySelector('.video-lightbox-gallery'); if (!gallery) return; // 只给最外层容器绑定一次点击事件 gallery.addEventListener('click', (e) => { // 判断点击目标是否是缩略图容器/其子元素,或者视频标题 const isThumbnailClick = e.target.closest('.thumbnail-wrapper'); const isTitleClick = e.target.closest('.video-title'); if (isThumbnailClick || isTitleClick) { console.log('event fired'); // 在这里补充你的业务逻辑 } }) isLightboxInit = true; }
如果你不想调整事件绑定逻辑,也可以在绑定事件前先移除旧监听器,需要把回调函数提取为命名函数:
export const lightbox = () => { const thumbnails = document.querySelectorAll('.video-lightbox-gallery .thumbnail-wrapper'); const titles = document.querySelectorAll('.video-lightbox-gallery .video-title'); setClickEvents(thumbnails) setClickEvents(titles) // 提取命名回调函数 function handleClick() { console.log('event fired'); } function setClickEvents(arr) { arr.forEach(item => { // 先移除之前绑定的同类型事件,再新增 item.removeEventListener('click', handleClick); item.addEventListener('click', handleClick); }) } }
补充检查点:可以排查是否有其他业务逻辑重复调用lightbox函数,或者页面是否意外存在多个.video-lightbox-gallery容器。
内容的提问来源于stack exchange,提问作者Koshua
相关产品推荐
相关产品推荐

