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
介面會公開 InvokeAsync 和 InvokeVoidAsync 方法以叫用 JavaScript 程式碼。 請使用 InvokeAsync<TValue>
來呼叫會傳回值的 JavaScript 函式。 否則,請呼叫 InvokeVoidAsync
。 正如其名,這兩種方法都是非同步方法,因此請使用 C# await
運算子來擷取結果。
InvokeAsync
或 InvokeVoidAsync
方法的參數是所要叫用的 JavaScript 函式所具有的名稱,再加上函式所需的任何引數。 JavaScript 函式必須是 window
範圍的一部分,或是 window
的子範圍。 引數必須可進行 JSON 序列化。
注意
只有在 Blazor Server 應用程式已建立與瀏覽器的 SignalR 連線時,才能使用 JS Interop。 在轉譯完成之前,您無法進行 Interop 呼叫。 若要偵測轉譯是否已完成,請在 Blazor 程式碼中使用 OnAfterRender 或 OnAfterRenderAsync 事件。
使用 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
類別會公開 invokeMethod
和 invokeMethodAsync
協助程式函式。 請使用 invokeMethod
來執行方法並等候結果,或使用 invokeMethodAsync
以非同步方式呼叫方法。 invokeMethodAsync
方法會傳回 JavaScript Promise
。
提示
若要讓應用程式保有回應能力,請將 .NET 方法定義為 async
,並從 JavaScript 使用 invokeMethodAsync
來呼叫此方法。
您必須使用 JSInvokableAttribute 來標記所呼叫的 .NET 方法。 該方法必須是 public
,而且任何參數都必須可進行 JSON 序列化。 此外,針對非同步方法,傳回型別必須是 void
、Task
或泛型 Task<T>
物件,其中 T
是 JSON 可序列化型別。
若要呼叫 static
方法,您可以提供包含類別的 .NET 組件名稱、方法的識別碼,以及方法可接受作為 invokeMethod
或 invokeMethodAsync
函式引數的任何參數。 根據預設,方法識別碼與方法的名稱相同,但是您可以使用 JSInvokable
屬性指定不同的值。
從 JavaScript 呼叫 .NET 執行個體方法
若要執行執行個體方法,JavaScript 需要指向執行個體的物件參考。 JS Interop 提供可用來在 .NET 程式碼中建立物件參考的泛型 DotNetObjectReference 型別。 該程式碼必須讓這個物件參考可供 JavaScript 使用。
然後,JavaScript 程式碼便可以使用 .NET 方法的名稱和方法所需的任何參數來呼叫 invokeMethodAsync
。 為了避免記憶體流失,.NET 程式碼應處置不再需要的物件參考。