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

JavaScript如何移除message事件处理程序解决事件重复触发问题

问题原因

你每次触发message事件渲染菜单时,都会通过$(document).on()给对应选项按钮新增一次点击委托事件,且从未移除旧的事件处理程序,菜单每开闭一次就多绑定一次事件,最终触发时会重复执行对应次数的逻辑。

解决方案

使用jQuery的事件命名空间特性实现精准清理,不会影响页面其他无关的点击事件,有两种可选实现方式:

方案1:绑定新事件前自动清理旧事件

每次给选项按钮绑定点击事件前,先移除同命名空间下的旧事件,从根源避免重复绑定:

window.addEventListener('message', function(event) {
  const MenuName = event.data.MenuName
  const MenuTitle = event.data.MenuTitle
  const MenuOptions = event.data.MenuOptions
  if (MenuName == 'MainMenu') {
    $('#npc-header').html(MenuTitle);
    // 先把多余的选项隐藏,避免循环重复执行
    for (let i = MenuOptions.length; i < 6; i++) {
      $("#option" + i).hide();
    }
    for (let i = 0; i < MenuOptions.length; i++) {
      if (i <= 6) {
        $("#option" + i).show();
        $("#option" + i).html(MenuOptions[i].Title);
        // 绑定前先移除同命名空间的旧事件
        $(document).off('click.menuOption', "#option" + i).on('click.menuOption', "#option" + i, function() {
          if (MenuOptions[i].Type == 'Menu') {
            if (MenuOptions[i].Title == 'Settings') {
              $.post('https://DokusCore--Menu/OpenSettingsMenu', JSON.stringify({}));
            }
            if (MenuOptions[i].Title == 'Functions') {
              $.post('https://DokusCore--Menu/OpenFunctionsMenu', JSON.stringify({}));
            }
            if (MenuOptions[i].Title == 'Music') {
              $.post('https://DokusCore--Menu/OpenMusicMenu', JSON.stringify({}));
            }
          } else if (MenuOptions[i].Type == 'Option') {
            if (MenuOptions[i].Title == 'Open Inventory') {
              $.post('https://DokusCore--Menu/Close', JSON.stringify({}));
              $('body').fadeOut();
              $.post('https://DokusCore--Menu/OpenInventory', JSON.stringify({}));
            }
          }
        });
      }
    }
  }
  if (MenuName == 'SettingsMenu') {
    $('#npc-header').html(MenuTitle);
    // 先把多余的选项隐藏,避免循环重复执行
    for (let i = MenuOptions.length; i < 6; i++) {
      $("#option" + i).hide();
    }
    for (let i = 0; i < MenuOptions.length; i++) {
      if (i <= 6) {
        $("#option" + i).show();
        $("#option" + i).html(MenuOptions[i].Title);
        // 绑定前先移除同命名空间的旧事件
        $(document).off('click.menuOption', "#option" + i).on('click.menuOption', "#option" + i, function() {
          if (MenuOptions[i].Type == 'Menu') {
          } else if (MenuOptions[i].Type == 'Option') {
            if (MenuOptions[i].Title == 'Toggle Music') {
              $.post('https://DokusCore--Menu/ToggleMusic', JSON.stringify({}));
            }
          }
        });
      }
    }
  }
  $('body').fadeIn();
});
// Close the menu
$(document).on('click', ".btn-closeinterface", function() {
  $('body').fadeOut();
  $.post('https://DokusCore--Menu/Close', JSON.stringify({}));
});

方案2:关闭菜单时统一清理所有事件

如果不需要在切换菜单(比如从主菜单切到设置菜单)时保留事件,可以在关闭菜单的逻辑里统一清空所有菜单相关的绑定事件:

// Close the menu
$(document).on('click', ".btn-closeinterface", function() {
  // 统一清理所有选项按钮的绑定事件
  for (let i = 0; i <= 6; i++) {
    $(document).off('click.menuOption', "#option" + i);
  }
  $('body').fadeOut();
  $.post('https://DokusCore--Menu/Close', JSON.stringify({}));
});

额外优化

你原有代码里的内层循环复用了变量名i,会导致变量污染、隐藏逻辑出错,已经在上面的示例代码里把这部分逻辑提到外层,避免重复执行和变量冲突。

内容的提问来源于stack exchange,提问作者DevDokus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 07:15:10