SuperAPI AI 工具集

use-js-interop

编程与开发

查看项目

更新于 10-16 16:39

技能介绍

本技能用于在 Blazor 组件中添加、审查或修复 JavaScript 互操作(JS Interop)代码,适用场景包括从 Blazor 调用 JavaScript、从 JavaScript 调用 .NET,以及使用同目录 .razor.js 模块等。

一、同目录 JS 模块 应始终使用与组件同目录的 .razor.js 文件并通过 export 导出函数,不要使用全局 window.* 函数或 <script> 标签。示例中 ChartPanel.razor.js 与 ChartPanel.razor 放在一起,导出 initialize、updateData、dispose 等函数。导入路径规则:同一项目使用 "./Components/ChartPanel.razor.js",RCL 使用 "./_content/{AssemblyName}/..."。

二、生命周期时机 所有 JS 互操作必须发生在 OnAfterRenderAsync 或事件处理器中,不能在 OnInitialized、OnParametersSet 或构造函数中调用,因为服务端预渲染期间 JS 不可用。应使用强类型互操作包装类,不要用原始字符串字面量调用 InvokeAsync/InvokeVoidAsync。参数变化时,在 OnParametersSet 中设置标志,在 OnAfterRenderAsync 中应用。

三、批量合并相关操作 每次 JS 互操作调用都会跨越 .NET 到 JS 的边界(在 Blazor Server 中还会经过 SignalR 线路),双向都适用批量合并。.NET→JS:若 C# 侧连续发起两个或更多 JS 调用,应合并为一个 JS 函数;若一个调用的结果作为另一个调用的输入,可整体保留在 JS 中。JS→.NET:当 JS 需要回传多项数据时,用单次 invokeMethodAsync 调用发送,而不是多次回调。规则是:如果两个互操作调用总是成对发生,就合并为一个函数。

四、强类型互操作包装类 将某个功能的互操作封装在一个普通类中,由该类负责模块生命周期。示例 ChartInterop 实现 IAsyncDisposable,内部定义 ModulePath、InitMethod、UpdateMethod、DisposeMethod 等 internal const 常量,通过 GetModuleAsync 惰性导入模块,提供 InitializeAsync、UpdateDataAsync、DisposeAsync 方法。组件通过 @inject IJSRuntime JS 使用该包装类,无魔法字符串。互操作包装类优先使用具体类而非接口加实现;单元测试时可直接替换 IJSRuntime(它本身已是接口)。

五、DotNetObjectReference 用于 JS 到 .NET 回调 通过 DotNetObjectReference.Create(this) 创建引用并传给 JS。JS 侧应将 dotNetRef 包装在类中,使用 async/await 配合 try/catch(而非 .catch())防止线路断开,并在顶部定义 .NET 方法名常量。规则包括:[JSInvokable] 方法必须是 public,private/internal 会在运行时静默失败;在 [JSInvokable] 回调中把 StateHasChanged 包在 InvokeAsync 内;JS 侧 invokeMethodAsync 始终 try/catch,线路断开会抛异常;JS 中用 const 定义 .NET 方法名字符串以防拼写错误静默失败;在 DisposeAsync 中释放 DotNetObjectReference。

六、释放与服务端安全 始终实现 IAsyncDisposable,先调用 JS 清理,再释放引用,并捕获 Blazor Server 线路断开导致的 JSDisconnectedException。不要用同步 IDisposable 做 JS 互操作清理,因为 InvokeVoidAsync 返回 ValueTask,必须 await。

七、ElementReference 通过 @ref 传递 DOM 元素,而不是字符串 ID。

文末提供检查清单(同目录 .razor.js 且 export、互操作位于 OnAfterRenderAsync 或事件处理器、IAsyncDisposable 捕获 JSDisconnectedException、释放 DotNetObjectReference 且 JS 侧 try/catch、[JSInvokable] 为 public 且用 await InvokeAsync(StateHasChanged)、无返回值时用 InvokeVoidAsync、使用 ElementReference、批量合并相关操作)以及常见错误对照表,例如用 JS 做 CSS 可完成的事、过多细粒度互操作调用、组件直接导入 JS 模块、方法名与模块路径使用魔法字符串、互操作包装类用接口加实现、在 OnInitializedAsync 中调用 JS、void 调用用 InvokeAsync<object>、用 IDisposable 配合 fire-and-forget JS、全局 window.* 函数、传字符串元素 ID、[JSInvokable] 标注私有方法、未释放 DotNetObjectReference、未用 InvokeAsync 包裹 StateHasChanged、JS invokeMethodAsync 无错误处理、JS 事件处理器中裸用 dotNetRef、JS invokeMethodAsync 使用魔法字符串、在 OnParametersSetAsync 中调用 JS、调用模块前未做 null 检查等,并给出对应修复方式。