Blazor WebAssembly可以在瀏覽器上跑C#代碼,但是很多時候顯然還是需要跟JavaScript打交道。比如操作dom,當然跟angular、vue一樣不提倡直接操作dom;比如瀏覽器的後退導航。反之JavaScript也有可能需要調用C#代碼來實現一些功能,畢竟客戶的需求是千變萬化的, ...
Blazor WebAssembly可以在瀏覽器上跑C#代碼,但是很多時候顯然還是需要跟JavaScript打交道。比如操作dom,當然跟angular、vue一樣不提倡直接操作dom;比如瀏覽器的後退導航。反之JavaScript也有可能需要調用C#代碼來實現一些功能,畢竟客戶的需求是千變萬化的,有的時候只能通過一些hack的手段來實現。
.NET調用JavaScript函數
使用JSRuntime.InvokeVoidAsync調用無返回值的JavaScript函數
顯然我們的.NET類庫里不會有JavaScript內置的alert方法來顯示提示,這裡演示下如何調用JavaScript的alert方法:
<h3>.net call javascript</h3>
<button @onclick="CallJs">
Call alert
</button>
@inject IJSRuntime jsRuntime
@code {
private void CallJs()
{
jsRuntime.InvokeVoidAsync("alert", "this message from .net runtime .");
}
}
使用JSRuntime.InvokeVoidAsync調用具有返回值的JavaScript函數
我們在JavaScript環境定義一個加法函數然後.NET這邊調用拿到結果:
<script>
function add(a, b) {
return a + b;
}
</script>
註意:JavaScript代碼要放到wwwroot/index.html頁面上里,不能直接放在組件里。
組件代碼:
<h3>.net call javascript</h3>
sum: @sum
<button @onclick="CallJs">
Call Add
</button>
@inject IJSRuntime jsRuntime
@code {
private int sum = 0;
private async void CallJs()
{
sum = await jsRuntime.InvokeAsync<int>("add", sum, 2);
this.StateHasChanged();
}
}
運行一下:
JavaScript調用.NET方法
JavaScript調用.NET靜態方法
JavaScript調用.NET靜態方法比較簡單,把靜態方法加上[JSInvokable],然後在JavaScript環境使用DotNet對象直接call就行:
定義.NET靜態方法:
[JSInvokable]
public static string GetNow()
{
return DateTime.Now.ToString();
}
使用JavaScript調用GetNow:
$(document).ready(
setTimeout(() => {
$('#btn1').on('click', function () {
DotNet.invokeMethodAsync('BlazorWasmComponent', 'GetNow')
.then(data => {
alert(data);
});
})
}, 10000)
);
由於Blazor渲染UI結束後按鈕才會插入到dom樹上,所以這裡使用一個傻辦法讓綁定事件的JavaScript代碼置後運行。
運行一下:
JavaScript調用組件里的方法
JavaScript調用組件里的方法比較繞,其實還是通過一個靜態方法作為入口,把實例方法綁定一個靜態delegate,然後讓這個靜態方法去執行delegate。
.NET代碼:
<h3>javascript call .net</h3>
<button id="btn1">
Js call .net
</button>
@inject IJSRuntime jsRuntime
@code {
[JSInvokable]
public static string GetNow()
{
return Act("");
}
public static Func<string, string> Act;
protected override void OnInitialized()
{
Act = GetNowInInstance;
base.OnInitialized();
}
public string GetNowInInstance(string str)
{
return DateTime.Now.ToString();
}
}
JavaScript代碼:
$(document).ready(
setTimeout(() => {
$('#btn1').on('click', function () {
DotNet.invokeMethodAsync('BlazorWasmComponent', 'GetNow')
.then(data => {
alert(data);
});
})
}, 10000)
);
運行一下:
調用對象的方法
Blazor還可以把.NET對象(引用)直接傳遞到JavaScript運行時來讓JavaScript直接調用.NET對象的方法。
總的來說大概分4步:
- 實例化.net對象
- DotNetObjectReference.Create方法把.NET對象包裝
- 通過JSRuntime調用一個JavaScript方法把第二步生成的對象傳遞到JavaScript運行時
- 在JavaScript側通過invokeMethodAsync方法調用.NET對象里的方法
下麵演示下把組件整個實例傳遞出去,然後調用裡面的GetNowInInstance方法。
.net代碼:
<h3>javascript call .net</h3>
<button id="btn1">
Js call .net
</button>
@implements IDisposable
@inject IJSRuntime jsRuntime
@code {
IDisposable _objRef;
protected async override Task OnInitializedAsync()
{
_objRef = DotNetObjectReference.Create(this);
await jsRuntime.InvokeAsync<string>(
"receiveNetObj",
_objRef);
base.OnInitialized();
}
[JSInvokable]
public string GetNowInInstance()
{
return DateTime.Now.ToString();
}
public void Dispose()
{
_objRef?.Dispose();
}
}
註意:把.NET對象傳遞到JavaScript運行時存在記憶體泄漏的風險,所以組件需要實現IDisposable介面,在Dispose方法內調用objRef的Dispose方法來釋放記憶體。
JavaScript代碼:
var _netObj = null;
function receiveNetObj(obj) {
_netObj = obj;
}
$(document).ready(
setTimeout(() => {
$('#btn1').on('click', function () {
_netObj.invokeMethodAsync("GetNowInInstance").then(
r => alert(r)
);
})
}, 10000)
);
運行一下:
總結
使用JSRuntime可以在.NET里調用JavaScript的方法,這些方法必須是全局的,也就是掛載在window對象上的。
在JavaScript里調用.NET方法主要有兩種:
- 通過DotNet方式調用.NET的靜態方法
- 把.NET對象直接傳遞到JavaScript運行時來調用對象上的方法
相關內容
ASP.NET Core Blazor Webassembly 之 路由
ASP.NET Core Blazor Webassembly 之 數據綁定
ASP.NET Core Blazor Webassembly 之 組件
ASP.NET Core Blazor 初探之 Blazor WebAssembly
ASP.NET Core Blazor 初探之 Blazor Server