JavaScript [JSImport]
/[JSExport]
Interop 搭配 ASP.NET Core Blazor
注意
這不是這篇文章的最新版本。 如需目前版本,請參閱本文的 .NET 8 版本。
本文說明如何使用針對採用 .NET 7 或更新版本的應用程式的 JavaScript (JS) [JSImport]
/[JSExport]
Interop API,與用戶端元件中的 JavaScript (JS) 互動。
Blazor 會根據 IJSRuntime 介面提供自己的 JS Interop 機制。 Blazor 跨轉譯模式和 Blazor Hybrid 應用程式都一致支援 Blazor 的 JS Interop。 IJSRuntime 也可讓程式庫作者建置可跨 Blazor 生態系統共用的 JS Interop 程式庫,並且仍然是 Blazor 中 JS Interop 的建議方法。 請參閱以下文章:
本文描述在 WebAssembly 上執行的用戶端元件特定的替代 JS Interop 方法。 當您只預期在用戶端 WebAssembly 上執行時,這些方法就很合適。 程式庫作者可以使用這些方法來最佳化 JS Interop,方法是在程式碼執行期間檢查應用程式是否在瀏覽器 (OperatingSystem.IsBrowser) 中的 WebAssembly 上執行。 本文所述的方法應該用來在移轉至 .NET 7 或更新版本時取代過時的解除封送 JS Interop API。
注意
本文著重於用戶端元件中的 JS Interop。 如需在 JavaScript 應用程式中呼叫 .NET 的指導,請參閱從 JavaScript 執行 .NET。
過時的 JavaScript Interop API
使用 IJSUnmarshalledRuntime API 解除封送的 JS Interop 在 .NET 7 或更新版本的 ASP.NET Core 中已淘汰。 遵循本文中的指導來取代過時的 API。
必要條件
如果尚未安裝在系統上,或系統尚未安裝最新版本,請下載並安裝 .NET 7 或更新版本。
Namespace
本文所述的 JS Interop API 是由 System.Runtime.InteropServices.JavaScript 命名空間中的屬性所控制。
啟用不安全的區塊
啟用應用程式專案檔中的 AllowUnsafeBlocks 屬性,其會允許 Roslyn 編譯器中的程式碼產生器使用指標進行 JS Interop:
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
警告
JS Interop API 需要啟用 AllowUnsafeBlocks。 在 .NET 應用程式中實作本身不安全的程式碼時請小心,這可能會帶來安全性和穩定性風險。 如需詳細資訊,請參閱不安全的程式碼、指標型別和函式指標。
從 .NET 呼叫 JavaScript
本節說明如何從 .NET 呼叫 JS 函式。
在下列 CallJavaScript1
元件中:
CallJavaScript1
模組會以非同步方式從共置的 JS 檔案使用 JSHost.ImportAsync 匯入。- 匯入的
getMessage
JS 函式是由GetWelcomeMessage
呼叫。 - 傳回的歡迎訊息字串會透過
message
欄位顯示在 UI 中。
CallJavaScript1.razor
:
@page "/call-javascript-1"
@rendermode InteractiveWebAssembly
@using System.Runtime.InteropServices.JavaScript
<h1>
JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop
(Call JS Example 1)
</h1>
@(message is not null ? message : string.Empty)
@code {
private string? message;
protected override async Task OnInitializedAsync()
{
await JSHost.ImportAsync("CallJavaScript1",
"../Components/Pages/CallJavaScript1.razor.js");
message = GetWelcomeMessage();
}
}
@page "/call-javascript-1"
@using System.Runtime.InteropServices.JavaScript
<h1>
JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop
(Call JS Example 1)
</h1>
@(message is not null ? message : string.Empty)
@code {
private string? message;
protected override async Task OnInitializedAsync()
{
await JSHost.ImportAsync("CallJavaScript1",
"../Pages/CallJavaScript1.razor.js");
message = GetWelcomeMessage();
}
}
注意
使用 OperatingSystem.IsBrowser 在程式碼中包含條件式簽入,以確保 JS Interop 只會由用戶端上轉譯的元件呼叫。 對於以伺服器端元件為目標的程式庫/NuGet 封裝 (其無法執行此 JS Interop API 所提供的程式碼),這很重要。
若要匯入 JS 函式以從 C# 呼叫它,請在符合 JS 函式簽章的 C# 方法簽章上使用 [JSImport]
屬性。 [JSImport]
屬性的第一個參數是要匯入 JS 函式的名稱,而第二個參數是 JS 模組的名稱。
在下列範例中,getMessage
是針對名為 CallJavaScript1
的模組傳回 string
的 JS 函式。 C# 方法簽章相符:不會將任何參數傳遞至 JS 函式,而 JS 函式會傳回 string
。 JS 函式是由 GetWelcomeMessage
在 C# 程式碼中呼叫。
CallJavaScript1.razor.cs
:
using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;
namespace BlazorSample.Components.Pages;
[SupportedOSPlatform("browser")]
public partial class CallJavaScript1
{
[JSImport("getMessage", "CallJavaScript1")]
internal static partial string GetWelcomeMessage();
}
上述 CallJavaScript1
部分類別的應用程式命名空間為 BlazorSample
。 元件的命名空間為 BlazorSample.Components.Pages
。 如果在本機測試應用程式中使用上述元件,請更新命名空間以符合應用程式。 例如,如果應用程式的命名空間是 ContosoApp
,則命名空間為 ContosoApp.Components.Pages
。 如需詳細資訊,請參閱 ASP.NET Core Razor 元件。
using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;
namespace BlazorSample.Pages;
[SupportedOSPlatform("browser")]
public partial class CallJavaScript1
{
[JSImport("getMessage", "CallJavaScript1")]
internal static partial string GetWelcomeMessage();
}
上述 CallJavaScript1
部分類別的應用程式命名空間為 BlazorSample
。 元件的命名空間為 BlazorSample.Pages
。 如果在本機測試應用程式中使用上述元件,請更新命名空間以符合應用程式。 例如,如果應用程式的命名空間是 ContosoApp
,則命名空間為 ContosoApp.Pages
。 如需詳細資訊,請參閱 ASP.NET Core Razor 元件。
在匯入的方法簽章中,您可以使用 .NET 型別作為參數和傳回值,其會由執行階段自動封送處理。 使用 JSMarshalAsAttribute<T> 來控制匯入的方法參數如何封送處理。 例如,您可以選擇將 long
封送處理為 System.Runtime.InteropServices.JavaScript.JSType.Number 或 System.Runtime.InteropServices.JavaScript.JSType.BigInt。 您可以將 Action/Func<TResult> 回呼作為參數傳遞,這些回呼會封送為可呼叫的 JS 函式。 您可以傳遞 JS 和受控物件參考,而且它們會封送處理為 Proxy 物件,讓物件在跨邊界保持運作,直到 Proxy 被垃圾回收為止。 您也可以使用 Task 結果匯入和匯出非同步方法,這些方法會按照 JS Promises 進行封送處理。 大部分封送處理型別可以以參數和傳回值形式,在匯入和匯出方法上雙向運作,本文稍後的從 JavaScript 呼叫 .NET 小節將會說明。
下表指出支援的型別對應。
.NET | JavaScript | Nullable |
Task 至Promise |
JSMarshalAs 選用 |
Array of |
---|---|---|---|---|---|
Boolean |
Boolean |
支援 | 支援 | 支援 | 不支援 |
Byte |
Number |
支援 | 支援 | 支援 | 支援 |
Char |
String |
支援 | 支援 | 支援 | 不支援 |
Int16 |
Number |
支援 | 支援 | 支援 | 不支援 |
Int32 |
Number |
支援 | 支援 | 支援 | 支援 |
Int64 |
Number |
支援 | 支援 | 不支援 | 不支援 |
Int64 |
BigInt |
支援 | 支援 | 不支援 | 不支援 |
Single |
Number |
支援 | 支援 | 支援 | 不支援 |
Double |
Number |
支援 | 支援 | 支援 | 支援 |
IntPtr |
Number |
支援 | 支援 | 支援 | 不支援 |
DateTime |
Date |
支援 | 支援 | 不支援 | 不支援 |
DateTimeOffset |
Date |
支援 | 支援 | 不支援 | 不支援 |
Exception |
Error |
不支援 | 支援 | 支援 | 不支援 |
JSObject |
Object |
不支援 | 支援 | 支援 | 支援 |
String |
String |
不支援 | 支援 | 支援 | 支援 |
Object |
Any |
不支援 | 支援 | 不支援 | 支援 |
Span<Byte> |
MemoryView |
不支援 | 不支援 | 不支援 | 不支援 |
Span<Int32> |
MemoryView |
不支援 | 不支援 | 不支援 | 不支援 |
Span<Double> |
MemoryView |
不支援 | 不支援 | 不支援 | 不支援 |
ArraySegment<Byte> |
MemoryView |
不支援 | 不支援 | 不支援 | 不支援 |
ArraySegment<Int32> |
MemoryView |
不支援 | 不支援 | 不支援 | 不支援 |
ArraySegment<Double> |
MemoryView |
不支援 | 不支援 | 不支援 | 不支援 |
Task |
Promise |
不支援 | 不支援 | 支援 | 不支援 |
Action |
Function |
不支援 | 不支援 | 不支援 | 不支援 |
Action<T1> |
Function |
不支援 | 不支援 | 不支援 | 不支援 |
Action<T1, T2> |
Function |
不支援 | 不支援 | 不支援 | 不支援 |
Action<T1, T2, T3> |
Function |
不支援 | 不支援 | 不支援 | 不支援 |
Func<TResult> |
Function |
不支援 | 不支援 | 不支援 | 不支援 |
Func<T1, TResult> |
Function |
不支援 | 不支援 | 不支援 | 不支援 |
Func<T1, T2, TResult> |
Function |
不支援 | 不支援 | 不支援 | 不支援 |
Func<T1, T2, T3, TResult> |
Function |
不支援 | 不支援 | 不支援 | 不支援 |
下列條件適用於型別對應和封送處理值:
Array of
資料行會指出 .NET 型別是否可封送處理為 JSArray
。 範例:C#int[]
(Int32
) 對應至 JSNumber
的Array
。- 將 JS 值傳遞至使用錯誤型別值的 C# 時,架構在大部分情況下會擲回例外狀況。 架構不會在 JS 中執行編譯時間型別檢查。
JSObject
、Exception
、Task
和ArraySegment
建立GCHandle
及 Proxy。 您可以在開發人員程式碼中觸發處置,或稍後允許 .NET 記憶體回收 (GC) 處置物件。 這些型別具有顯著的效能額外負荷。Array
:封送處理陣列會在 JS 或 .NET 中建立陣列的複本。MemoryView
MemoryView
是 .NET WebAssembly 執行階段的 JS 類別,用於封送處理Span
和ArraySegment
。- 與封送處理陣列不同,封送處理
Span
或ArraySegment
不會建立基礎記憶體的複本。 MemoryView
只能由 .NET WebAssembly 執行階段正確具現化。 因此,無法將 JS 函式匯入為具有Span
或ArraySegment
參數的 .NET 方法。- 為
Span
建立的MemoryView
只在 Interop 呼叫期間才有效。 如同Span
在呼叫堆疊上配置,在 Interop 呼叫之後不會保存,因此無法匯出傳回Span
的 .NET 方法。 - 針對
ArraySegment
建立的MemoryView
在 Interop 呼叫之後存留下來,而且有助於共用緩衝區。 在針對ArraySegment
建立的MemoryView
上呼叫dispose()
會處置 Proxy,並取消釘選基礎 .NET 陣列。 我們建議在MemoryView
的dispose()
區塊中呼叫try-finally
。
下表指出支援的型別對應。
.NET | JavaScript | Nullable |
Task 至Promise |
JSMarshalAs 選用 |
Array of |
---|---|---|---|---|---|
Boolean |
Boolean |
支援 | 支援 | 支援 | 不支援 |
Byte |
Number |
支援 | 支援 | 支援 | 支援 |
Char |
String |
支援 | 支援 | 支援 | 不支援 |
Int16 |
Number |
支援 | 支援 | 支援 | 不支援 |
Int32 |
Number |
支援 | 支援 | 支援 | 支援 |
Int64 |
Number |
支援 | 支援 | 不支援 | 不支援 |
Int64 |
BigInt |
支援 | 支援 | 不支援 | 不支援 |
Single |
Number |
支援 | 支援 | 支援 | 不支援 |
Double |
Number |
支援 | 支援 | 支援 | 支援 |
IntPtr |
Number |
支援 | 支援 | 支援 | 不支援 |
DateTime |
Date |
支援 | 支援 | 不支援 | 不支援 |
DateTimeOffset |
Date |
支援 | 支援 | 不支援 | 不支援 |
Exception |
Error |
不支援 | 支援 | 支援 | 不支援 |
JSObject |
Object |
不支援 | 支援 | 支援 | 支援 |
String |
String |
不支援 | 支援 | 支援 | 支援 |
Object |
Any |
不支援 | 支援 | 不支援 | 支援 |
Span<Byte> |
MemoryView |
不支援 | 不支援 | 不支援 | 不支援 |
Span<Int32> |
MemoryView |
不支援 | 不支援 | 不支援 | 不支援 |
Span<Double> |
MemoryView |
不支援 | 不支援 | 不支援 | 不支援 |
ArraySegment<Byte> |
MemoryView |
不支援 | 不支援 | 不支援 | 不支援 |
ArraySegment<Int32> |
MemoryView |
不支援 | 不支援 | 不支援 | 不支援 |
ArraySegment<Double> |
MemoryView |
不支援 | 不支援 | 不支援 | 不支援 |
Task |
Promise |
不支援 | 不支援 | 支援 | 不支援 |
Action |
Function |
不支援 | 不支援 | 不支援 | 不支援 |
Action<T1> |
Function |
不支援 | 不支援 | 不支援 | 不支援 |
Action<T1, T2> |
Function |
不支援 | 不支援 | 不支援 | 不支援 |
Action<T1, T2, T3> |
Function |
不支援 | 不支援 | 不支援 | 不支援 |
Func<TResult> |
Function |
不支援 | 不支援 | 不支援 | 不支援 |
Func<T1, TResult> |
Function |
不支援 | 不支援 | 不支援 | 不支援 |
Func<T1, T2, TResult> |
Function |
不支援 | 不支援 | 不支援 | 不支援 |
Func<T1, T2, T3, TResult> |
Function |
不支援 | 不支援 | 不支援 | 不支援 |
下列條件適用於型別對應和封送處理值:
Array of
資料行會指出 .NET 型別是否可封送處理為 JSArray
。 範例:C#int[]
(Int32
) 對應至 JSNumber
的Array
。- 將 JS 值傳遞至使用錯誤型別值的 C# 時,架構在大部分情況下會擲回例外狀況。 架構不會在 JS 中執行編譯時間型別檢查。
JSObject
、Exception
、Task
和ArraySegment
建立GCHandle
及 Proxy。 您可以在開發人員程式碼中觸發處置,或稍後允許 .NET 記憶體回收 (GC) 處置物件。 這些型別具有顯著的效能額外負荷。Array
:封送處理陣列會在 JS 或 .NET 中建立陣列的複本。MemoryView
MemoryView
是 .NET WebAssembly 執行階段的 JS 類別,用於封送處理Span
和ArraySegment
。- 與封送處理陣列不同,封送處理
Span
或ArraySegment
不會建立基礎記憶體的複本。 MemoryView
只能由 .NET WebAssembly 執行階段正確具現化。 因此,無法將 JS 函式匯入為具有Span
或ArraySegment
參數的 .NET 方法。- 為
Span
建立的MemoryView
只在 Interop 呼叫期間才有效。 如同Span
在呼叫堆疊上配置,在 Interop 呼叫之後不會保存,因此無法匯出傳回Span
的 .NET 方法。 - 針對
ArraySegment
建立的MemoryView
在 Interop 呼叫之後存留下來,而且有助於共用緩衝區。 在針對ArraySegment
建立的MemoryView
上呼叫dispose()
會處置 Proxy,並取消釘選基礎 .NET 陣列。 我們建議在MemoryView
的dispose()
區塊中呼叫try-finally
。
[JSImport]
屬性中的模組名稱,以及使用 JSHost.ImportAsync 在元件中載入模組的呼叫必須相符且在應用程式中是唯一的。 撰寫程式庫以在 NuGet 封裝中部署時,建議您使用 NuGet 封裝命名空間作為模組名稱的前置詞。 在下列範例中,模組名稱會反映 Contoso.InteropServices.JavaScript
封裝和使用者訊息 Interop 類別的資料夾 (UserMessages
):
[JSImport("getMessage",
"Contoso.InteropServices.JavaScript.UserMessages.CallJavaScript1")]
可在全域命名空間上存取的函式,可以在函式名稱中使用 globalThis
前置詞,以及使用 [JSImport]
屬性而不提供模組名稱來匯入。 在下列範例中,console.log
的前置詞為 globalThis
。 匯入的函式是由 C# Log
方法呼叫,其會接受 C# 字串訊息 (message
) 並將 C# 字串封送處理為 console.log
的 JSString
:
[JSImport("globalThis.console.log")]
internal static partial void Log([JSMarshalAs<JSType.String>] string message);
從標準 JavaScript ES6 模組匯出指令碼,以與元件共置,或與其他 JavaScript 靜態資產放置在 JS 檔案中 (例如,wwwroot/js/{FILE NAME}.js
,其中的 JS 靜態資產會保留在應用程式 wwwroot
資料夾中名為 js
的資料夾中,而 {FILE NAME}
預留位置是檔案名稱)。
在下列範例中,名為 getMessage
的 JS 函式會從共置的 JS 檔案匯出,其會傳回葡萄牙文的歡迎訊息 "Hello from Blazor!":
CallJavaScript1.razor.js
:
export function getMessage() {
return 'Olá do Blazor!';
}
從 JavaScript 呼叫 .NET
本節說明如何從 JS 呼叫 .NET 方法。
下列 CallDotNet1
元件會呼叫直接與 DOM 互動以轉譯歡迎訊息字串的 JS:
CallDotNet
JS 模組會從此元件的共置 JS 檔案非同步匯入。- 匯入的
setMessage
JS 函式是由SetWelcomeMessage
呼叫。 - 傳回的歡迎訊息字串會由
setMessage
透過message
欄位顯示在 UI 中。
重要
在本節的範例中,JS Interop 是用來在 OnAfterRender
中轉譯元件之後,純粹為了示範目的而變動 DOM 元素。 一般而言,您只應該在物件未與 Blazor 互動時使用 JS 來變動 DOM。 本節中顯示的方法與 Razor 元件中使用的第三方 JS 程式庫的情況類似,其中元件會透過 JS Interop 與 JS 程式庫互動,第三方 JS 程式庫會與 DOM 的一部分互動,而 Blazor 不會直接與對 DOM 部分的 DOM 更新相關。 如需詳細資訊,請參閱 ASP.NET Core Blazor JavaScript 互通性 (JS Interop)。
CallDotNet1.razor
:
@page "/call-dotnet-1"
@rendermode InteractiveWebAssembly
@using System.Runtime.InteropServices.JavaScript
<h1>
JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop
(Call .NET Example 1)
</h1>
<p>
<span id="result">.NET method not executed yet</span>
</p>
@code {
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JSHost.ImportAsync("CallDotNet1",
"../Components/Pages/CallDotNet1.razor.js");
SetWelcomeMessage();
}
}
}
@page "/call-dotnet-1"
@using System.Runtime.InteropServices.JavaScript
<h1>
JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop
(Call .NET Example 1)
</h1>
<p>
<span id="result">.NET method not executed yet</span>
</p>
@code {
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JSHost.ImportAsync("CallDotNet1",
"../Pages/CallDotNet1.razor.js");
SetWelcomeMessage();
}
}
}
若要匯出 .NET 方法,以便從 JS 呼叫它,請使用 [JSExport]
屬性。
在以下範例中:
SetWelcomeMessage
會呼叫名為setMessage
的 JS 函式。 JS 函式會呼叫 .NET,以接收來自GetMessageFromDotnet
的歡迎訊息,並在 UI 中顯示訊息。GetMessageFromDotnet
是 .NET 方法,其[JSExport]
屬性會以葡萄牙文傳回歡迎訊息 "Hello from Blazor!"。
CallDotNet1.razor.cs
:
using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;
namespace BlazorSample.Components.Pages;
[SupportedOSPlatform("browser")]
public partial class CallDotNet1
{
[JSImport("setMessage", "CallDotNet1")]
internal static partial void SetWelcomeMessage();
[JSExport]
internal static string GetMessageFromDotnet()
{
return "Olá do Blazor!";
}
}
上述 CallDotNet1
部分類別的應用程式命名空間為 BlazorSample
。 元件的命名空間為 BlazorSample.Components.Pages
。 如果在本機測試應用程式中使用上述元件,請更新應用程式命名空間以符合應用程式。 例如,如果應用程式的命名空間是 ContosoApp
,則元件命名空間為 ContosoApp.Components.Pages
。 如需詳細資訊,請參閱 ASP.NET Core Razor 元件。
在下列範例中,名為 setMessage
的 JS 函式會從共置的 JS 檔案匯入。
setMessage
方法:
- 呼叫
globalThis.getDotnetRuntime(0)
以公開 WebAssembly .NET 執行階段執行個體,以呼叫匯出的 .NET 方法。 - 取得應用程式元件的 JS 匯出。 下列範例中應用程式元件的名稱為
BlazorSample
。 - 從匯出 (
exports
) 呼叫BlazorSample.Components.Pages.CallDotNet1.GetMessageFromDotnet
方法。 傳回的值,即歡迎訊息,會指派給CallDotNet1
元件的<span>
文字。 應用程式的命名空間為BlazorSample
,而CallDotNet1
元件的命名空間為BlazorSample.Components.Pages
。
CallDotNet1.razor.js
:
export async function setMessage() {
const { getAssemblyExports } = await globalThis.getDotnetRuntime(0);
var exports = await getAssemblyExports("BlazorSample.dll");
document.getElementById("result").innerText =
exports.BlazorSample.Components.Pages.CallDotNet1.GetMessageFromDotnet();
}
using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;
namespace BlazorSample.Pages;
[SupportedOSPlatform("browser")]
public partial class CallDotNet1
{
[JSImport("setMessage", "CallDotNet1")]
internal static partial void SetWelcomeMessage();
[JSExport]
internal static string GetMessageFromDotnet()
{
return "Olá do Blazor!";
}
}
上述 CallDotNet1
部分類別的應用程式命名空間為 BlazorSample
。 元件的命名空間為 BlazorSample.Pages
。 如果在本機測試應用程式中使用上述元件,請更新應用程式命名空間以符合應用程式。 例如,如果應用程式的命名空間是 ContosoApp
,則元件命名空間為 ContosoApp.Pages
。 如需詳細資訊,請參閱 ASP.NET Core Razor 元件。
在下列範例中,名為 setMessage
的 JS 函式會從共置的 JS 檔案匯入。
setMessage
方法:
- 呼叫
globalThis.getDotnetRuntime(0)
以公開 WebAssembly .NET 執行階段執行個體,以呼叫匯出的 .NET 方法。 - 取得應用程式元件的 JS 匯出。 下列範例中應用程式元件的名稱為
BlazorSample
。 - 從匯出 (
exports
) 呼叫BlazorSample.Pages.CallDotNet1.GetMessageFromDotnet
方法。 傳回的值,即歡迎訊息,會指派給CallDotNet1
元件的<span>
文字。 應用程式的命名空間為BlazorSample
,而CallDotNet1
元件的命名空間為BlazorSample.Pages
。
CallDotNet1.razor.js
:
export async function setMessage() {
const { getAssemblyExports } = await globalThis.getDotnetRuntime(0);
var exports = await getAssemblyExports("BlazorSample.dll");
document.getElementById("result").innerText =
exports.BlazorSample.Pages.CallDotNet1.GetMessageFromDotnet();
}
注意
呼叫 getAssemblyExports
以取得匯出可能發生在 JavaScript 初始化運算式中,以取得整個應用程式的可用性。
多個模組匯入呼叫
載入 JS 模組之後,只要應用程式在瀏覽器視窗或索引標籤中執行,模組的 JS 函式就可供應用程式的元件和類別使用,而不需要使用者手動重新載入應用程式。 JSHost.ImportAsync 可以在相同的模組上呼叫多次,而不會在下列情況下大幅降低效能:
- 使用者會瀏覽呼叫 JSHost.ImportAsync 以匯入模組的元件、導覽離開元件,然後返回元件,在其中會再次呼叫 JSHost.ImportAsync 以取得相同模組匯入。
- 相同模組會由不同的元件使用,並由 JSHost.ImportAsync 在每個元件中載入。
跨元件使用單一 JavaScript 模組
遵循本節中的指導之前,請閱讀本文的從 .NET 呼叫 JavaScript 和從 JavaScript 呼叫 .NET 小節,其中提供有關 [JSImport]
/[JSExport]
Interop 的一般指導。
本節中的範例示範如何從用戶端應用程式中的共用 JS 模組使用 JS Interop。 本節中的指導不適用 Razor 類別庫 (RCL)。
使用下列元件、類別、C# 方法和 JS 函式:
Interop
類別 (Interop.cs
):使用名為Interop
的模組的[JSImport]
和[JSExport]
屬性,設定匯入和匯出 JS Interop。GetWelcomeMessage
:呼叫匯入的getMessage
JS 函式的 .NET 方法。SetWelcomeMessage
:呼叫匯入的setMessage
JS 函式的 .NET 方法。GetMessageFromDotnet
:匯出的 C# 方法,會在從 JS 呼叫時傳回歡迎訊息字串。
wwwroot/js/interop.js
檔案:包含 JS 函式。getMessage
:在元件中由 C# 程式碼呼叫時傳回歡迎訊息。setMessage
:呼叫GetMessageFromDotnet
C# 方法,並將傳回的歡迎訊息指派給 DOM<span>
元素。
Program.cs
呼叫 JSHost.ImportAsync 以從wwwroot/js/interop.js
載入模組。CallJavaScript2
元件 (CallJavaScript2.razor
):在元件的 UI 中呼叫GetWelcomeMessage
並顯示傳回的歡迎訊息。CallDotNet2
元件 (CallDotNet2.razor
):呼叫SetWelcomeMessage
。
Interop.cs
:
using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;
namespace BlazorSample.JavaScriptInterop;
[SupportedOSPlatform("browser")]
public partial class Interop
{
[JSImport("getMessage", "Interop")]
internal static partial string GetWelcomeMessage();
[JSImport("setMessage", "Interop")]
internal static partial void SetWelcomeMessage();
[JSExport]
internal static string GetMessageFromDotnet()
{
return "Olá do Blazor!";
}
}
在上述範例中,應用程式的命名空間是 BlazorSample
,而 C# Interop 類別的完整命名空間為 BlazorSample.JavaScriptInterop
。
wwwroot/js/interop.js
:
export function getMessage() {
return 'Olá do Blazor!';
}
export async function setMessage() {
const { getAssemblyExports } = await globalThis.getDotnetRuntime(0);
var exports = await getAssemblyExports("BlazorSample.dll");
document.getElementById("result").innerText =
exports.BlazorSample.JavaScriptInterop.Interop.GetMessageFromDotnet();
}
讓 System.Runtime.InteropServices.JavaScript 命名空間在 Program.cs
檔案頂端提供:
using System.Runtime.InteropServices.JavaScript;
在呼叫 WebAssemblyHost.RunAsync 之前在 Program.cs
中載入模組:
if (OperatingSystem.IsBrowser())
{
await JSHost.ImportAsync("Interop", "../js/interop.js");
}
CallJavaScript2.razor
:
@page "/call-javascript-2"
@rendermode InteractiveWebAssembly
@using BlazorSample.JavaScriptInterop
<h1>
JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop
(Call JS Example 2)
</h1>
@(message is not null ? message : string.Empty)
@code {
private string? message;
protected override void OnInitialized()
{
message = Interop.GetWelcomeMessage();
}
}
@page "/call-javascript-2"
@using BlazorSample.JavaScriptInterop
<h1>
JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop
(Call JS Example 2)
</h1>
@(message is not null ? message : string.Empty)
@code {
private string? message;
protected override void OnInitialized()
{
message = Interop.GetWelcomeMessage();
}
}
CallDotNet2.razor
:
@page "/call-dotnet-2"
@rendermode InteractiveWebAssembly
@using BlazorSample.JavaScriptInterop
<h1>
JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop
(Call .NET Example 2)
</h1>
<p>
<span id="result">.NET method not executed</span>
</p>
@code {
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
Interop.SetWelcomeMessage();
}
}
}
@page "/call-dotnet-2"
@using BlazorSample.JavaScriptInterop
<h1>
JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop
(Call .NET Example 2)
</h1>
<p>
<span id="result">.NET method not executed</span>
</p>
@code {
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
Interop.SetWelcomeMessage();
}
}
}
重要
在本節的範例中,JS Interop 是用來在 OnAfterRender
中轉譯元件之後,純粹為了示範目的而變動 DOM 元素。 一般而言,您只應該在物件未與 Blazor 互動時使用 JS 來變動 DOM。 本節中顯示的方法與 Razor 元件中使用的第三方 JS 程式庫的情況類似,其中元件會透過 JS Interop 與 JS 程式庫互動,第三方 JS 程式庫會與 DOM 的一部分互動,而 Blazor 不會直接與對 DOM 部分的 DOM 更新相關。 如需詳細資訊,請參閱 ASP.NET Core Blazor JavaScript 互通性 (JS Interop)。
其他資源
- API 文件
- 從 JavaScript 執行 .NET
- 在
dotnet/runtime
GitHub 存放庫中:
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應