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
相关产品推荐
相关产品推荐

