升级Blazor WebAssembly至.NET 7后index.html脚本加载失效
.NET 7 Blazor WASM动态注入JS脚本失效的原因与修复
失效原因
.NET 7对Blazor WASM的启动流程做了调整:Blazor.start()返回的Promise会在Blazor运行时初始化完成、但组件尚未开始渲染时就完成回调。而你通过动态创建script标签注入的MyJS.js是异步加载的,当Blazor组件尝试调用其中的函数时,脚本大概率还没加载完成,直接导致函数未定义的错误。
你提到的缓存问题不是本次失效的直接原因,但可以结合修复方案一并解决。
修复方案(保留动态注入方式)
方案1:先加载脚本,再启动Blazor
这是最稳妥的方式,确保Blazor组件渲染时,JS函数已经完全可用,同时添加缓存破击参数避免缓存:
<script src="_framework/blazor.webassembly.js"></script> <script> function loadJSHelper() { return new Promise((resolve, reject) => { const JSHelperScript = document.createElement('script'); // 添加时间戳作为版本参数,避免缓存 JSHelperScript.src = '/_content/SampleApp/scripts/MyJS.js?v=' + Date.now(); JSHelperScript.onload = resolve; JSHelperScript.onerror = () => reject(new Error('Failed to load MyJS.js')); document.head.appendChild(JSHelperScript); }); } // 先完成脚本加载,再启动Blazor loadJSHelper() .then(() => Blazor.start()) .catch(err => { console.error(err.message); // 脚本加载失败时仍启动Blazor,可根据业务需求调整 Blazor.start(); }); </script>
方案2:保留原启动时机,监听脚本加载状态
如果坚持要在Blazor.start().then()中注入脚本,需要在JS脚本和Blazor组件之间添加加载状态同步逻辑:
- 修改
MyJS.js,加载完成后主动通知Blazor:
// MyJS.js // 封装所有函数到全局对象 window.MyJS = { targetFunction: function() { // 你的函数逻辑 } }; // 通知Blazor脚本已加载完成 if (window.Blazor?.notifyJSLoaded) { window.Blazor.notifyJSLoaded(); }
- 在
index.html中添加状态监听逻辑:
<script src="_framework/blazor.webassembly.js"></script> <script> window.Blazor = window.Blazor || {}; window.Blazor._jsLoaded = false; window.Blazor._jsLoadResolver = null; // 供Blazor调用的等待方法 window.Blazor.waitForJS = () => { return new Promise(resolve => { if (window.Blazor._jsLoaded) { resolve(true); } else { window.Blazor._jsLoadResolver = resolve; } }); }; // 供JS脚本调用的通知方法 window.Blazor.notifyJSLoaded = () => { window.Blazor._jsLoaded = true; window.Blazor._jsLoadResolver?.(); }; Blazor.start().then(() => { const JSHelperScript = document.createElement('script'); JSHelperScript.src = '/_content/SampleApp/scripts/MyJS.js?v=' + Date.now(); document.head.appendChild(JSHelperScript); }); </script>
- 在Blazor组件中等待脚本加载完成后再调用函数:
@inject IJSRuntime JS protected override async Task OnInitializedAsync() { // 等待JS脚本加载完成 await JS.InvokeAsync<bool>("Blazor.waitForJS"); // 调用MyJS中的函数 await JS.InvokeVoidAsync("MyJS.targetFunction"); }
缓存优化补充
不管用哪种注入方式,给脚本URL添加动态版本参数都是避免缓存的可靠方式:
- 用时间戳:
?v=' + Date.now(),每次加载都生成新URL,适合开发环境 - 用项目版本号:发布时替换为固定版本号(比如
?v=1.0.0),适合生产环境,可通过Razor语法注入项目版本:
<script src="/_content/SampleApp/scripts/MyJS.js?v=@(typeof(Program).Assembly.GetName().Version)"></script>
内容的提问来源于stack exchange,提问作者Sean
相关产品推荐
相关产品推荐

