大家好,我是Edison。
在上一篇我們學習了Blazor+SignalR開發簡單的實時應用程序,這一篇我們瞭解下Blazor和JavaScript的互操作性。
有了Blazor還需要JavaScript?
我們都知道,在Blazor中我們可以輕鬆地使用C#組件而不是JavaScript來創建Web應用程序,但是,這並不代表我們不能繼續使用JavaScript提供的便利。很
多時候,我們可能希望繼續使用JavaScript提供的函數來實現某些功能,這時,我們可以用Blazor和JavaScript的互操作性(也稱爲JS互操作)來調用Blazor應用中的JavaScript庫,並從C#代碼直接調用JavaScript函數。當然,也可以使用JS互操作性從JavaScript函數調用C#方法。
這種場景經常發生在:有時候需要使用現有的JavaScript庫,例如一些開源JavaScript庫以專門的方式呈現組件和處理用戶界面元素,又或者你可能擁有一些開源JavaScript庫的開發調試經驗,是個JavaScript庫的老鳥了,你希望重用該JavaScript代碼而不是將其轉換爲C#。那麼,這個時候,你可能就需要用上JS互操作性了。
接下來,我們就來看看如何在Blazor應用中加載JavaScript代碼,又如何在JavaScript中調用.NET代碼。
在Blazor中調用JavaScript代碼
加載方式
將JavaScript添加到Blazor應用的方式與添加到標準HTML Web應用一樣,都是使用HTML的<script>元素。我們可以在 Pages/_Layout.cshtml 文件或 wwwroot/index.html文件中的現有 <script src="_framework/blazor.*.js"></script>
標記後添加 <script>
標記即可。
NOTE:最好不要將JavaScript腳本放在頁面的<head>元素中。
將JavaScript庫或腳本添加之後,我們就可以在C#代碼中通過使用 IJSRuntime 接口調用JavaScript函數了。不過,你需要提前將 IJSRuntime 實例注入Blazor頁面中。
IJSRuntime 接口用於調用JavaScript代碼的 InvokeAsync(有返回值) 和 InvokeVoidAsync(無返回值) 兩個方法。顧名思義,這兩個方法都是異步的,因此你需要在使用時標註await來獲取結果。
InvokeAsync 或 InvokeVoidAsync 方法的接收參數,第一個是要調用的JavaScript函數的名稱,比如 confirm 這個方法名。第二個則是這個函數所需的任何參數。
需要注意的是:
-
JavaScript函數必須屬於 window 作用域 或 window 子作用域;
-
傳入的參數必須是可序列化爲JSON的;
DEMO
假設我們已經有了一個Blazor Server應用程序,你可以從這裏獲取Code:https://github.com/Coder-EdisonZhou/BlazorSamples。
這裏我們改寫一下經典的Counter頁面,將原來的按鈕直接加一改爲調用JavaScript的confirm函數彈出一個確認框,確認後再加一。
爲了實現這個功能,我們需要改寫如下:
Step1. 注入IJSRuntime抽象實例
[Inject] public IJSRuntime JavaScript { get; set; }
Step2. 改寫原來的button按鈕調用IncrementCountConfirmation方法
@* <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> *@ <button class="btn btn-primary" @onclick="@(async() => await IncrementCountConfirmation())">Click me</button>
Step3. 實現IncrementCountConfirmation方法
@code { private int currentCount = 0; [Parameter] public int IncrementAmount { get; set; } = 1; [Inject] public IJSRuntime JavaScript { get; set; } private void IncrementCount() { currentCount += IncrementAmount; } private async Task IncrementCountConfirmation() { if (await JavaScript.InvokeAsync<bool>( "confirm", "Do you want to increment the count?")) { currentCount += IncrementAmount; } } }
最終的效果如下圖:
那麼,如果想要使用第三方JavaScript庫的函數該如何做呢?
<script src="_framework/blazor.*.js"></script>
標記後添加你需要引入的JavaScript庫即可。在JavaScript中調用C#代碼
加載方式
在JavaScript中若想調用C#代碼可以使用 DotNet實用工具類(JS互操作的一部分)來運行Blazor代碼中定義的.NET方法。在這個工具類中提供了 invokeMethod 和 invokeMethodAsync 兩個函數,顧名思義,一個是同步的,另一個是異步的。
invokeMethodAsync方法返回 JavaScript Promise。
需要注意的是:
-
要調用的.NET方法需要使用 JSInvokableAttribute 標記
-
且該方法必須是 public的
-
且該方法任何參數都必須可序列化爲JSON
DEMO
這裏我們還是改寫一下剛剛的Counter頁面,增加一個button用於在JavaScript中調用.NET靜態方法。
Step1. 添加HTML與JavaScript
<h1>Call .NET Example From JavaScript</h1> <p> <button onclick="returnArrayAsync()"> Trigger .NET static method </button> </p> <script> window.returnArrayAsync = () => { DotNet.invokeMethodAsync('EDT.BlazorServer.App', 'ReturnArrayAsync') .then(data => { console.log(data); }); }; </script>
Step2. 添加.NET方法並標註 JSInvokable
[JSInvokable] public static Task<int[]> ReturnArrayAsync() { return Task.FromResult(new int[] { 1, 2, 3 }); }
效果演示:
那麼,如果是.NET實例方法,該如何調用呢?這個就稍微複雜一丟丟了。
還是來個Demo吧:
Step1. 添加HTML和JavaScript示例:
<h1>Call .NET Example From JavaScript - Sample 2</h1> <p> <label> Name: <input @bind="name" /> </label> </p> <p> <button @onclick="TriggerDotNetInstanceMethod"> Trigger .NET instance method </button> </p> <p> @result </p> <script> window.sayHello = (dotNetHelper) => { return dotNetHelper.invokeMethodAsync('GetHelloMessage'); }; </script>
Step2. 添加.NET方法並標註 JSInvokable,還需要聲明一個 DotNetObjectReference對象便於進行資源釋放,以免引起內存泄露的問題;
@code { [Inject] public IJSRuntime JavaScript { get; set; } private string? name; private string? result; private DotNetObjectReference<Counter>? objRef; protected override void OnInitialized() { objRef = DotNetObjectReference.Create(this); } public async Task TriggerDotNetInstanceMethod() { result = await JavaScript.InvokeAsync<string>("sayHello", objRef); } [JSInvokable] public string GetHelloMessage() => $"Hello, {name}!"; public void Dispose() { objRef?.Dispose(); } }
效果演示:
小結
本篇,我們瞭解了什麼是Blazor中的JS互操作,並通過兩個DEMO瞭解瞭如何在Blazor中加載JavaScript代碼 以及 如何在JavaScript中調用.NET代碼,相信對你會有所幫助。
參考代碼
GitHub:https://github.com/EdisonChou/BlazorSamples/tree/main