Blazor JavaScript 互操作性
关于 JavaScript 位置
在 标记中加载脚本
<head>
<script src="js/first.js"></script>
<script>
window.jsMethod = (methodParameter) => {
...
};
</script>
</head>
在 标记中加载脚本
<body>
<script src="js/first.js"></script>
<script>
window.jsMethod = (methodParameter) => {
...
};
</script>
</body>
组件并置
组件:CountComponent.razor
组件:CountComponent.razor.cs
样式:CountComponent.razor.css
脚本:CountComponent.razor.js
从.NET 调用 JS
在 wwwroot 下创建 app.js 文件
function helloWorld() {
alert('Hello World');
}
function add(a, b) {
return a + b;
}
在 App.razor 中引入 JS 文件
当前 Web 项目脚本引入
<head>
<script src="@Assets["app.js"]"></script>
</head>
如果使用了 RCL 组件库
<head>
<script src="_content/LibraryName/app.js"></script>
</head>
在 .NET 组件中调用 JS 方法
@inject IJSRuntime JS
<button class="btn btn-primary" @onclick="SayHello">SayHello</button>
<button class="btn btn-primary" @onclick="Add">Add</button>
<p>Current count: @result</p>
@code {
private int result = 0;
private async Task SayHello()
{
await JS.InvokeVoidAsync("helloWorld");
}
private async Task Add()
{
result = await JS.InvokeAsync<int>("add", result, 1);
StateHasChanged();
}
}
基于模块化的 JS 文件
export function helloWorld() {
alert('Hello World');
}
export function add(a, b) {
return a + b;
}
在 MyComponent.razor 组件中写如下代码
@inject IJSRuntime JS
@implements IAsyncDisposable
@code {
private IJSInProcessObjectReference? module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
var jsInProcess = (IJSInProcessRuntime)JS;
module = await JS.InvokeAsync<IJSInProcessObjectReference>("import", "./path/to/MyComponent.razor.js");
var value = module.Invoke<string>("javascriptFunctionIdentifier");
}
}
async ValueTask IAsyncDisposable.DisposeAsync()
{
try
{
if (module is not null)
{
await module.DisposeAsync();
}
}
catch (JSDisconnectedException)
{
}
}
}
<div @ref="divElement" style="margin-top:2000px">
Set value via JS interop call: <strong>@scrollPosition</strong>
</div>
@code {
private ElementReference divElement;
private int scrollPosition;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
var jsInProcess = (IJSInProcessRuntime)JS;
var module = await jsInProcess.InvokeAsync<IJSInProcessObjectReference>("import", "./path/to/MyComponent.razor.js");
scrollPosition = await module.InvokeAsync<int>("getScrollPosition", divElement);
}
}
}
从 JS 调用 .NET 方法
提供两个静态方法
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});
DotNet.invokeMethod('{ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});
在 C## 组件中提供一个静态方法
@code {
[JSInvokable]
public static Task{<T>} {.NET METHOD ID}()
{
...
}
}
可以指定参数修改方法名
[JSInvokable("DifferentMethodName")]
public static Task{<T>} {.NET METHOD ID}()
{
...
}
通过 dotNetHelper 调用 .NET 方法
通过将实例包装在 DotNetObjectReference 中并对其调用 Create,将 .NET 实例通过引用传递给 JS。
@inject IJSRuntime JS
@implements IAsyncDisposable
@code {
private DotNetObjectReference<MyComponent>? dotNetHelper;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
dotNetHelper = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync("jsFunction", dotNetHelper);
}
}
public async ValueTask DisposeAsync()
{
if (dotNetHelper is not null)
{
await dotNetHelper.DisposeAsync();
}
}
}