iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 22
1
Modern Web

大內魔術 Blazor - 誰說前端一定要寫JS系列 第 22

魔術技巧 - 與 JavaScript 共舞

  • 分享至 

  • xImage
  •  

今天要來介紹在 Blazor WebAssembly 與 JavaScript 的互動方式,也就是 JavaScript interop,畢竟目前有些行為如果不透過 JavaScript 是無法實現的,如在魔術技巧 - 取得元件參考提到的 Focus 元素等 DOM 的操作 ,與使用 windows 物件提供的成員。所以目前的 Blazor WebAssembly 還是需要借助撰寫 JavaScript 來達成特地行為。


要從 .NET 呼叫 JavaScript,只需要在元件注入 JSRuntime 即可如:

@inject IJSRuntime JSRuntime

並且透過 InvokeAsync 來呼叫指定的 JavaScript 函式,而其參數有:

  • identifier(string):呼叫方法的識別碼,是相對於全域範圍(window),也就是如果想要呼叫 window.someScope.someFunction,則識別碼為 someScope.someFunction

  • args(Object[]):呼叫方法的引數陣列,也就是如果呼叫的 JavaScript 方法需要兩個參數,就寫兩個引數,但要注意每個引數都必須是能夠 JSON 序列化。

  • cancellationToken(CancellationToken):發出取消操作的信號,指定此參數將覆蓋所有預設的取消信號,例如因為超時(DefaultAsyncTimeout)而導致的取消。

  • timeout(TimeSpan):超過指定時間則取消操作,指定此參數將覆蓋預設時間。

而傳回值為 ValueTask<TValue>TValue 應符合最適合對應至 JavaScript 所傳回 JSON 型別的 .NET 型別,且如果 JavaScript 傳回的是 Promise,則會拆開並傳回 Promise 所等待的結果。

倘若 JavaScript 是傳回 void(0)/void,則可以使用 InvokeVoidAsync 來表示,其參數與上述相同。

而撰寫 JavaScript 時,建議是新增 .js 檔在 wwwroot 目錄下,並透過引用的方法加在 wwwroot/index.html 中如:

<!--wwwroot/index.html-->
<script src="exampleJsInterop.js"></script>

切勿將 <script> 標籤放在元件檔中,因為 <script> 無法動態變更。

在大部分情況下請不要透過 JavaScript 來修改 DOM,因為 JavaScript 可能會干擾 Blazor 的變更追蹤。


如果要反過來,使用 JavaScript 來呼叫 .NET 程式碼也是可行的,只需要建立帶有 [JSInvokable] 屬性的公開靜態方法即可如:

[JSInvokable]
public static int Sum(int a, int b) => a + b;

而 JavaScript 的呼叫方式為:

DotNet.invokeMethodAsync('{APP ASSEMBLY}', 'Sum', 1, 2)
  .then(data => {
    console.log(data);
  });

其中的 {APP ASSEMBLY} 是應用程式的名稱,也就是說如果有兩個以上一樣名稱的公開靜態方法,就會因為不知道需要執行誰而導致程式錯誤。

要解決這個問題,我們可以將元件功能抽成一個服務,在傳送資料給 JavaScript 時,可以透過 DotNetObjectReference 將服務包在裡面,使得 JavaScript 呼叫 .NET 方法時,可以直接呼叫服務的方法,如:

// Day22SampleService.cs
public class Day22SampleService
{
  [JSInvokable]
  public int Sum(int a, int b) => a + b;
}
// Day22Sample.razor
@code {
  private DotNetObjectReference<Day22SampleService> objRef;
  private async Task<string> callDotNetAndPrintData2()
  {
    objRef = DotNetObjectReference.Create(new Day22SampleService());
    return await JSRuntime.InvokeAsync<string>("exampleJsFunctions.callDotNetAndPrintData2", objRef);
  }
}
// js
window.exampleJsFunctions = {
  callDotNetAndPrintData2: function (dotnetHelper) {
    return dotnetHelper.invokeMethodAsync('Sum', 1, 3)
      .then(data => {
        console.log(data);
      });
  }
};

這樣一來就可以準確鎖定特定服務給 JavaScript 呼叫。


以上就是 .NET 與 JavaScript 的互動方式,如果想看完整範例可以參考範本程式碼 - day22

感謝大家的閱讀,我們明天見。

參考資料
從 .NET 呼叫 JavaScript
從 JavaScript 呼叫 .NET


上一篇
魔術技巧 - HTTP 要求與回應
下一篇
狀態管理魔術
系列文
大內魔術 Blazor - 誰說前端一定要寫JS30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言