Blazor入門筆記(3)-C#與JS交互


1.環境

VS2019 16.5.1

.NET Core SDK 3.1.200

Blazor WebAssembly Templates 3.2.0-preview2.20160.5

2.前言

Blazor的存在可以讓我們再前端以高性能運行代碼,但是有些時候我們不得不需要使用JS來進行一些操作,尤其是在使用第三方JS庫的時候,而在JS執行完畢后,可能還需要JS通知C#執行的結果,這時候就需要使用C#調用JS或者是JS調用C#。

3.C#調用JS 

3.1.函數定義

C#調用JS是通過IJSRuntime來實現的。IJSRuntime定義了兩個方法(當然,這兩個方法都有重載,但是這兩個方法是常見的):

ValueTask<TValue> InvokeAsync<TValue>(string identifier, object[] args);
ValueTask InvokeVoidAsync<TValue>(string identifier, object[] args);

InvokeAsync和InvokeVoidAsync的定義類似,形參identifier代表要執行的js函數名(要求必須掛載在window對象上),可以為JSON格式的標識,args則是js函數所需要的參數。其中,InvokeAsync用於執行有返回值的js函數,InvokeVoidAsync用於執行無返回值的js函數,這是兩者的區別。

我們可以看到,IJSRuntime中的這兩個函數都是異步函數,這是因為如果Blazor是服務端渲染的格式,其使用SignalR進行交互,JS互操作調用都必須是異步的。如果我們希望在WebAssembly應用程序(客戶端渲染)下同步調用js函數,則可以將IJSRuntime對象轉換為IJSInProcessRuntime對象,IJSInProcessRuntime對象中定義了一個同步方法Invoke,其形參與上述的兩個相同。

T Invoke<T>(string identifier, params object[] args)

注意:IJSRuntime在Server與Client渲染模式中都可以使用,IJSInProcessRuntime只可在Client渲染模式中使用。

3.2.IJSRuntime的注入

如果我們直接在razor組件中使用IJSRuntime對象,則可以通過@inject指令將IJSRuntime對象注入到組件中;如果我們需要在類中調用IJSRuntime對象,則需要使用Inject屬性注解進行注入:

//組件中注入
@inject IJSRuntime JsRuntime
//類中注入
[Inject]
public IJSRuntime JsRuntime { get; set; }

3.3.使用

新建一個Blazor WebAssembly應用程序,打開Index.razor頁面,在路由屬性下插入以下代碼:

@inject IJSRuntime JsRuntime
<div class="jumbotron bg-white border border-primary">
    <h5>C#與JS互操作</h5>
    <div>
        <button @onclick="OnClick" class="btn btn-primary">交互</button>
    </div>
</div>

在這里定義了一個button,並為它添加了onclick事件,注意我們在為HTML的原生事件添加綁定時,需要在事件前添加“@”符號。接下來,我們實現OnClick事件響應函數。OnClick函數的返回結果可以是Task,也可以為void,此外,還可以有一個事件參數(像js中定義事件函數一樣,可以不用寫e)。OnClick的定義如下:

private async Task OnClick(MouseEventArgs e)
{
    Console.WriteLine("OnClick is executing");
    var name = "world";
    var a = 11;
    var b = 22;
    var jsRunResult = await JsRuntime.InvokeAsync<string>("interop.runJs", name, a, b);
    Console.WriteLine($"interop.runJs return:{jsRunResult}");
}

在OnClick中使用JsRuntime調用了一個js函數runJs。runJs可以通過window.interop.runJs被調用。interop.runJs的定義如下(為了區分C# Console.WriteLine的輸出,這里使用console.warn,使兩者具備不同的背景色):

window.interop = {
    runJs: (name, a, b) => {
        console.warn("runJs is executing");
        console.warn("hello " + name);
        return "OK " + (a + b); 
    }
}

點擊“交互”按鈕,瀏覽器中控制台的輸出結果如下(WASM: 是C#Console.WriteLine默認輸出的前綴):

4.JS調用C#

從JS調用C#有兩種方式,一種是調用靜態方法,另外一種是調用實例方法,無論那種方式,C#中能被JS調用的函數都需要標注JSInvokable屬性注解。

4.1.靜態方法的調用

4.1.1.介紹

靜態方法的調用是通過DotNet.invokeMethod或DotNet.invokeMethodAsync來實現的:

DotNet.invokeMethod("程序集的名稱", "靜態方法名稱",參數1,…,參數n);

DotNet.invokeMethodAsync定義與DotNet.invokeMethod定義相似,兩者區別在於DotNet.invokeMethodAsync的返回值為Promise,DotNet.invokeMethod結果就是函數的返回值。

4.1.2.實例

首先,我們在Index頁面中定義一個靜態函數Sum:

[JSInvokable]
public static Task<int> Sum(int a, int b)
{
    Console.WriteLine("Sum is executing");
    return Task.FromResult(a + b);
}

Sum的作用就是將用於替換runJs中放入求和。

然后我們添加一個runCsharp JS函數,並修改runJs的返回值為”return "OK " + runCsharp(a, b);“。runCsharp的定義如下:

const runCsharp = (a, b) => {
    console.warn("runCsharp is executing");
    //invokeResult是Task序列化的結果
    let invokeResult = DotNet.invokeMethod("BlazorInterop", "Sum", a, b);
    if (invokeResult.isCompletedSuccessfully) {
        return invokeResult.result;
    }
    return -1;
};

點擊“交互”按鈕,瀏覽器中控制台的輸出結果如下:

注意:由於Sum的返回值為Task,因此其返回結果invokeResult是Task的序列化結果,通過DotNet.invokeMethodAsync(…).then(result=>)得到的result則是求和的結果。

4.2.實例方法的調用

4.2.1. 介紹 

實例方法顧名思義,是指利用組件的實例調用方法,因此需要先將要執行的函數所在類的實例(可以不是組件)傳遞到JS中。這個實例並不是單純的new的結果,而是使用DotNetObjectReference對new進行封裝的結果:

//組件實例封裝:
DotNetObjectReference.Create(this)
//類實例封裝:
var classInstance = new SomClass();
DotNetObjectReference.Create(classInstance)

4.2.2.實例 

首先,在Index頁面中定義一個新的button,並為這個button綁定事件方法OnClick2:

<button @onclick="OnClick2" class="btn btn-primary">交互2</button>

OnClick2的定義如下:

private void OnClick2()
{
    IJSInProcessRuntime SyncJsRuntime = JsRuntime as IJSInProcessRuntime;
    var a = 11;
    var b = 22;
    var jsRunResult = SyncJsRuntime.Invoke<string>("interop.runJs2",DotNetObjectReference.Create(this),a, b);
    Console.WriteLine($"interop.runJs2 return:{jsRunResult}");
}

OnClick2中使用IJSInProcessRuntime同步調用了一個JS函數runJs2:

runJs2: (objInstance, a, b) => {
    let invokeResult = objInstance.invokeMethod("Multiply", a, b);
    console.warn(invokeResult);
    return "OK:" + invokeResult;
}

runJs2有三個參數:對象實例、a、b,然后通過對象實例調用了Index組件中的一個Multiply函數對a、b進行求積。Multiply函數定義如下:

[JSInvokable]
public int Multiply(int a, int b)
{
    Console.WriteLine("Multiply is executing");
    return a * b;
}

點擊“交互2”按鈕,瀏覽器中控制台的輸出結果如下:

代碼:https://github.com/zxyao145/LearningBlazor/tree/master/BlazorInterop

本文參考:

從ASP.NET Core Blazor中的.NET方法調用JavaScript函數

從ASP.NET Core Blazor中的JavaScript函數調用.NET方法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM