Blazor WASM点击浏览器后退按钮后JavaScript脚本不执行问题求助
问题解决方法
根因分析
- 事件绑定逻辑仅写在首页
Index.razor的生命周期中,只有首页渲染时才会触发执行,导航到其他页面时首页未加载,自然不会绑定点击事件 - 未判断
OnAfterRenderAsync的firstRender参数,页面每次重渲染都会重复执行绑定逻辑,容易导致事件重复触发 - 现有JS逻辑没有做元素存在性校验,也没有重复绑定防护,DOM未完全加载时调用会抛出异常
修复步骤
1. 移动事件绑定逻辑到全局布局
将原本放在Index.razor的JS调用逻辑迁移到MainLayout.razor(全局布局文件,所有页面渲染都会加载该布局),同时添加首次渲染判断、销毁时事件移除逻辑,避免内存泄漏:
@inject IJSRuntime jsRuntime @implements IAsyncDisposable @code { private bool _hasRegisteredEvent = false; protected override async Task OnAfterRenderAsync(bool firstRender) { // 仅首次渲染时绑定事件,避免重复注册 if (firstRender && !_hasRegisteredEvent) { await jsRuntime.InvokeVoidAsync("slideNav"); _hasRegisteredEvent = true; } } // 布局销毁时移除事件监听,避免内存泄漏 public async ValueTask DisposeAsync() { await jsRuntime.InvokeVoidAsync("removeSlideNavListener"); } }
如果你的导航栏是单独封装的Razor组件,也可以把上述逻辑直接放到导航组件的代码中,只要保证该组件在所有页面都会渲染即可。
2. 优化JS事件绑定逻辑
修改App.js代码,添加重复绑定防护、元素判空、事件移除方法:
// 将回调函数和元素变量提到全局作用域,方便销毁时调用 let toggleNavBar; let hamburgerMenu, closeMenu, mainElement; window.slideNav = () => { mainElement = document.querySelector('#slider'); hamburgerMenu = document.querySelector('#hamburger-menu'); closeMenu = document.querySelector('#close-menu'); // 元素不存在时直接返回,避免抛出空指针异常 if (!mainElement || !hamburgerMenu || !closeMenu) return; // 先移除已有的监听,避免重复绑定 if (toggleNavBar) { hamburgerMenu.removeEventListener('click', toggleNavBar, false); closeMenu.removeEventListener('click', toggleNavBar, false); } toggleNavBar = () => { mainElement.classList.toggle('opened-menu'); }; hamburgerMenu.addEventListener('click', toggleNavBar, false); closeMenu.addEventListener('click', toggleNavBar, false); }; // 供Blazor销毁时调用的事件移除方法 window.removeSlideNavListener = () => { if (toggleNavBar && hamburgerMenu && closeMenu) { hamburgerMenu.removeEventListener('click', toggleNavBar, false); closeMenu.removeEventListener('click', toggleNavBar, false); } };
额外排查点
确认#slider、#hamburger-menu、#close-menu三个DOM元素是写在全局布局/全局导航组件中的,不是仅放在Index.razor里,否则导航到其他页面时这些元素会被移除,功能自然失效。
内容的提问来源于stack exchange,提问作者Asmussen
相关产品推荐
相关产品推荐

