Blazor多数场景可不写JavaScript,但需正确调用:JS须外置加载,通过IJSRuntime调用;Server与WASM机制不同,Server禁OnInitialized调JS,WASM支持IJSInProcessRuntime;JS回调C#需DotNetObjectReference并手动释放防泄漏。

Blazor 不是“不用写 JavaScript”,而是让你**多数场景可以不写 JavaScript**——但该用的时候还得用,而且得用对方式。直接在组件里写 JS 会破坏服务端预渲染、导致 SSR 失效,甚至引发 JSRuntime.InvokeAsync 在服务端未初始化的异常。
Blazor Server 和 Blazor WebAssembly 的 JS 调用机制完全不同
Blazor Server 通过 SignalR 建立 .NET 与浏览器之间的长连接,IJSRuntime 实际是代理调用;Blazor WebAssembly 则是在 WASM 运行时中直接桥接 JS 全局对象。这意味着:
-
IJSRuntime.InvokeVoidAsync("foo")在 Server 模式下可能因连接中断静默失败,在 WASM 下则会抛出JSException - Server 模式下不能在
OnInitialized中立即调用 JS(此时 DOM 可能未挂载),WASM 下可以但需确保OnAfterRender已触发 -
Microsoft.JSInterop.IJSInProcessRuntime仅在 WASM 中可用,Server 中调用会报NotSupportedException
从 C# 调用 JS 函数必须走 IJSRuntime,不能直接写 script 标签内联
在 .razor 文件里写 <script>function sayHi() { alert('hi') }</script> 是无效的:Blazor 组件生命周期管理 DOM,手动插入的 script 不会被执行,且每次重渲染都会被移除。
正确做法是:
- 把 JS 函数定义在
wwwroot/js/site.js(或任意静态资源路径),并在index.html(WASM)或_Host.cshtml(Server)中通过<script src="js/site.js"></script>加载 - 在组件中注入
@inject IJSRuntime JSRuntime - 调用时用
await JSRuntime.InvokeVoidAsync("sayHi")或await JSRuntime.InvokeAsync("getUserId") - 如果 JS 函数需要访问组件实例(比如回调后更新状态),必须用
DotNetObjectReference.Create(this)传入,并在 JS 中保存引用——否则组件销毁后回调会 crash
JS 回调 C# 时,DotNetObjectReference 必须手动释放
常见错误是只创建不释放,导致内存泄漏和跨组件调用混乱。例如在 JS 中绑定事件后未清理:
window.registerClickHandler = (dotnetRef) => {
document.body.addEventListener('click', () => dotnetRef.invokeMethodAsync('HandleClick'));
};
对应 C# 端必须在 Dispose 或 OnAfterRender 中显式释放:
- 组件类实现
IDisposable - 在
Dispose()中调用_objRef?.Dispose()(其中_objRef是DotNetObjectReference.Create(this)创建的) - 如果组件支持热重载(Hot Reload),
Dispose可能被多次调用,需加 null 检查
最易被忽略的是:JS 代码里对 DotNetObjectReference 的引用不会自动失效,即使 C# 对象已被 GC,JS 仍可能尝试调用已释放的实例——这会导致 System.ObjectDisposedException 或静默失败。务必在 JS 侧也做存在性检查,比如 if (dotnetRef && !dotnetRef.isDisposed)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











