網上的方法
1,用 JSInvokable 標記需要被 js 呼叫的靜態方法
/// <summary> /// 頁面視窗改變事件回撥 /// </summary> /// <param name="windowWidth"></param> /// <param name="windowHeight"></param> [JSInvokable] public static void ClientWindowResizeCallback(int windowWidth, int windowHeight) { PageResizeExcuter?.Invoke(windowWidth, windowHeight); }
2,js 透過 DotNet.invokeMethodAsync 呼叫這個方法
window.addEventListener("resize", (event) => { console.log(`視窗尺寸改變了!!!! w:${window.innerWidth} h:${window.innerHeight}`); // DotNet 是 blazor 內建的物件 // param 1 : 指定程式集 // param 2 : JSInvokable 標記的方法 // 後面跟方法的引數 DotNet.invokeMethodAsync("AJR.AGV.Experience", "ClientWindowResizeCallback", window.innerWidth, window.innerHeight); });
使用 DotNet.invokeMethodAsync 時,你不需要關心 JSInvokable 方法所在的類,只要需要提供該方法的程式集;
但是這種做法有個缺陷,因為是靜態方法,當多個瀏覽器觸發同一事件時,只有最後開啟的瀏覽器能正確觸發回撥
改進版
不再使用靜態方法,也不再使用內建的 DotNet 物件;
C# 仍然用 JSInvokable 標記需要被呼叫的方法
public class JSEventReceiver { public event Func<int, int, Task>? OnPageResize; /// <summary> /// 頁面視窗改變事件回撥 /// </summary> /// <param name="windowWidth"></param> /// <param name="windowHeight"></param> [JSInvokable] public void ClientWindowResizeCallback(int windowWidth, int windowHeight) { if (OnPageResize is null) return; var delegates = OnPageResize.GetInvocationList(); foreach (Func<int, int, Task> delegated in delegates) { try { delegated.Invoke(windowWidth, windowHeight); } catch (Exception ex) { OnPageResize -= delegated; } } } }
在頁面上我們直接用 JSEventReceiver 建立一個 DotNetObjectReference 物件,並把這個物件傳給前端 js,這樣前端用到的 DoNet 物件就是由當前頁面建立的,多個頁面不會互相干擾;
這裡的 JSEventReceiver 物件可以使用 Scope 注入,不想用注入就直接 new JSEventReceiver(); 效果是一樣的
razor
protected override async Task OnAfterRenderAsync(bool firstRender) { await base.OnAfterRenderAsync(firstRender); if (firstRender) { #region 一個 js 呼叫 c# 的例子 _JsEventReceiver.OnPageResize -= HandlePageResize; _JsEventReceiver.OnPageResize += HandlePageResize; // 使用 DotNetObjectReference 向 JS 傳遞例項 var dotNetObjectRef = DotNetObjectReference.Create(_JsEventReceiver); // 註冊 JavaScript 事件 await _IJsRuntime.InvokeVoidAsync("eventRegistResize", dotNetObjectRef); #endregion } }
如果使用傳入的 DoNetObjectReference 物件,js 裡就不再需要指定程式集了
js
function eventRegistResize(dotNetObjectRef) { window.addEventListener("resize", (event) => { console.log(`視窗尺寸改變了!!!! w:${window.innerWidth} h:${window.innerHeight}`); dotNetObjectRef.invokeMethodAsync("ClientWindowResizeCallback", window.innerWidth, window.innerHeight); }); }
另:
如果在 razor 元件裡使用事件,別忘了在元件銷燬時釋放事件,必須實現 IDisposable 介面,Dispose 方法才生效
@page "/" @implements IDisposable @code { public void Dispose() { _JsEventReceiver.OnPageResize -= HandlePageResize; } }