JavaScript 與 Blazor 的互通性

已完成

Blazor 會使用 C# 元件來建立具有動態內容的網頁或 HTML 區段,而不會使用 JavaScript 來進行此作業。 但您可以使用 Blazor JavaScript 互通性 (JS Interop) 在 Blazor 應用程式中呼叫 JavaScript 程式庫,以及從 .NET C# 程式碼呼叫 JavaScript 函式。

在本單元中,您會了解如何在 Blazor 頁面中從 C# 程式碼呼叫 JavaScript,以及如何從 JavaScript 函式叫用 C# 方法。 在下一個單元中,您會使用 JavaScript 程式庫中的警示元件來更新 Blazor 披薩外送網站。

使用 Blazor JavaScript 互通性

典型的 Blazor 元件會使用版面配置和使用者介面邏輯在執行階段轉譯 HTML。 您可以使用 C# 程式碼來處理與使用者和外部服務互動的事件與其他動態頁面功能。 在許多情況下,您不需要使用 JavaScript 程式碼。 相反地,您可以搭配使用 Blazor 與提供了許多對等功能的 .NET 程式庫。

不過,有時候您需要使用現有的 JavaScript 程式庫。 例如,某些 JavaScript 開放原始碼程式庫會以特製化方式轉譯元件和處理使用者介面元素。 或者,您也可能有已經嘗試並測試過的 JavaScript 程式碼,而您想要重複使用這個程式碼,而不是將其轉換成 C#。

您可以使用 Blazor JavaScript 互通性 (又稱 JS Interop) 將 JavaScript 程式庫整合到您的應用程式中。 您可以使用 JS Interop 從 .NET 方法呼叫 JavaScript 函式,以及從 JavaScript 函式叫用 .NET 方法。 JS Interop 會處理 Blazor 與 JavaScript 之間資料與物件參考的封送處理,以簡化兩者間的轉換程序。

在 Blazor 應用程式中載入 JavaScript 程式碼

您可以透過和將 JavaScript 新增至標準 HTML Web 應用程式一樣的方式,使用 HTML <script> 元素將 JavaScript 新增至 Blazor 應用程式。 視 Blazor 裝載模型而定,您可以在 Pages/_Host.cshtml 檔案或 wwwroot/index.html 檔案中將 <script> 標記新增至現有的 <script src="_framework/blazor.*.js"></script> 標記之後。 如需詳細資訊,請參閱 ASP.NET Core Blazor 裝載模型

最好不要將指令碼放在頁面的 <head> 元素中。 Blazor 只能控制 HTML 頁面 <body> 元素中的內容,因此如果指令碼相依於 Blazor,JS Interop 可能會失敗。 此外,由於需要花時間剖析 JavaScript 程式碼,頁面可能會比較慢才顯示出來。

<script> 標記的運作方式和在 HTML Web 應用程式中一樣。 您可以直接在標記本文中撰寫程式碼,也可以參考現有的 JavaScript 檔案。 如需詳細資訊,請參閱 ASP.NET Core Blazor JavaScript 互通性 (JS Interop):JavaScript 的位置

重要

請將 JavaScript 檔案放在 Blazor 專案的 wwwroot 資料夾下。

另一個選項是將參考 JavaScript 檔案的 <script> 元素動態插入 Pages/_Host.cshtml 頁面。 如果您需要根據只能在執行階段判斷的條件來載入不同的指令碼,這個方法會很實用。 如果您使用會在轉譯頁面後引發的事件來觸發邏輯,這個方法也可以加快應用程式的初始載入速度。 如需詳細資訊,請參閱 ASP.NET Core Blazor 啟動

從 .NET 程式碼呼叫 JavaScript

您可以使用 IJSRuntime 從 .NET 程式碼呼叫 JavaScript 函式。 若要讓 JS Interop 執行階段可供使用,請在靠近檔案頂端的 @page 指示詞後面,將 IJSRuntime 抽象概念的執行個體插入 Blazor 頁面。

IJSRuntime 介面會公開 InvokeAsyncInvokeVoidAsync 方法以叫用 JavaScript 程式碼。 請使用 InvokeAsync<TValue> 來呼叫會傳回值的 JavaScript 函式。 否則,請呼叫 InvokeVoidAsync。 正如其名,這兩種方法都是非同步方法,因此請使用 C# await 運算子來擷取結果。

InvokeAsyncInvokeVoidAsync 方法的參數是所要叫用的 JavaScript 函式所具有的名稱,再加上函式所需的任何引數。 JavaScript 函式必須是 window 範圍的一部分,或是 window 的子範圍。 引數必須可進行 JSON 序列化。

注意

只有在 Blazor Server 應用程式已建立與瀏覽器的 SignalR 連線時,才能使用 JS Interop。 在轉譯完成之前,您無法進行 Interop 呼叫。 若要偵測轉譯是否已完成,請在 Blazor 程式碼中使用 OnAfterRenderOnAfterRenderAsync 事件。

使用 ElementReference 物件來更新 DOM

Blazor 會以虛擬轉譯樹狀結構的形式來表示文件物件模型 (DOM)。 當頁面結構變更時,Blazor 會產生新的轉譯樹狀結構,其中包含差異。 當變更完成時,Blazor 會逐一查看這些差異,以更新瀏覽器所顯示的使用者介面,以及 JavaScript 所使用的 DOM 瀏覽器版本。

有許多第三方 JavaScript 程式庫可用來轉譯頁面上的元素,而且這些程式庫可以更新 DOM。 如果 JavaScript 程式碼修改 DOM 的元素,Blazor 的 DOM 複本可能不會再符合目前的狀態。 這種情況會造成非預期的行為,而且可能會帶來安全性風險。 請務必不要進行可能會造成 Blazor 的 DOM 檢視損毀的變更。

要處理這種情況,最簡單的方式是在 Blazor 元件中建立預留位置元素,而這個元素通常是空白的 <div @ref="placeHolder"></div> 元素。 Blazor 程式碼會將此程式碼解讀為空白,而且 Blazor 轉譯樹狀結構不會嘗試追蹤其內容。 您可以自由地將 JavaScript 程式碼元素新增至這個 <div>,而且 Blazor 不會嘗試對其進行變更。

Blazor 應用程式的程式碼會定義一個型別為 ElementReference 的欄位,以保存 <div> 元素的參考。 <div> 元素上的 @ref 屬性會設定此欄位的值。 然後,ElementReference 物件會傳遞至 JavaScript 函式,此函式可以使用這個參考將內容新增至 <div> 元素。

從 JavaScript 呼叫 .NET 程式碼

JavaScript 程式碼可以使用屬於 JS Interop 程式庫一部分的 DotNet 公用程式類別來執行 Blazor 程式碼所定義的 .NET 方法。 DotNet 類別會公開 invokeMethodinvokeMethodAsync 協助程式函式。 請使用 invokeMethod 來執行方法並等候結果,或使用 invokeMethodAsync 以非同步方式呼叫方法。 invokeMethodAsync 方法會傳回 JavaScript Promise

提示

若要讓應用程式保有回應能力,請將 .NET 方法定義為 async,並從 JavaScript 使用 invokeMethodAsync 來呼叫此方法。

您必須使用 JSInvokableAttribute 來標記所呼叫的 .NET 方法。 該方法必須是 public,而且任何參數都必須可進行 JSON 序列化。 此外,針對非同步方法,傳回型別必須是 voidTask 或泛型 Task<T> 物件,其中 T 是 JSON 可序列化型別。

若要呼叫 static 方法,您可以提供包含類別的 .NET 組件名稱、方法的識別碼,以及方法可接受作為 invokeMethodinvokeMethodAsync 函式引數的任何參數。 根據預設,方法識別碼與方法的名稱相同,但是您可以使用 JSInvokable 屬性指定不同的值。

從 JavaScript 呼叫 .NET 執行個體方法

若要執行執行個體方法,JavaScript 需要指向執行個體的物件參考。 JS Interop 提供可用來在 .NET 程式碼中建立物件參考的泛型 DotNetObjectReference 型別。 該程式碼必須讓這個物件參考可供 JavaScript 使用。

然後,JavaScript 程式碼便可以使用 .NET 方法的名稱和方法所需的任何參數來呼叫 invokeMethodAsync。 為了避免記憶體流失,.NET 程式碼應處置不再需要的物件參考。

檢定您的知識

1.

您應該在何處新增 script 標記以參考您在 Blazor 中包含的 JavaScript 檔案?

2.

您應該使用哪一種 C# 方法來執行會傳回 void 的 JavaScript 函式?