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

forEach循环中添加的点击事件监听器触发多次的问题如何解决

问题原因

你遇到的点击事件触发3次的问题,核心是事件监听器被重复绑定了3次,常见触发场景如下:

  1. 虽然JS模块仅加载一次,但lightbox()函数被重复执行了3次:动态导入只会加载模块代码一次,但导出的lightbox函数可以被多次调用,比如DOMContentLoaded事件被异常触发多次、其他业务逻辑重复调用了该函数等
  2. 你当前使用匿名函数作为事件回调,每次调用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 03:45:08