文章目录


1. 可放置JavaScript方法的位置

js方法可以在以下几个位置:

1.1 在​​head​​里(不推荐)

<head>
<script>
window.jsMethod = (methodParameter) => {
...
};
</script>
</head>

为什么不推荐这么放:如果JS依赖于Blazor,那么互操作就会失败。而且也可能会导致页面响应变慢。

1.2 在​​body​​里

<body>
<script src="_framework/blazor.{webassembly|server}.js"></script>
<script>
window.jsMethod = (methodParameter) => {
...
};
</script>
</body>

1.3 在Blazor启动之后注入js

首先将​​blazor.js​​​的​​autostart​​​设置为​​false​​​。然后调用​​Blaozr.start().then()​​方法注入脚本。

<body>
<script src="_framework/blazor.{webassembly|server}.js"
autostart="false">
//设置为false
</script>

<script>
Blazor.start().then(function () {
var customScript = document.createElement('script');
customScript.setAttribute('src', 'scripts.js');
document.head.appendChild(customScript);
});
</script>
</body>

2. C#方法调用JS方法

可以使用​​IJSRuntime​​对象调用js方法。主要有:


  1. ​IJSRuntime.InvokeAsync​​​:第一个参数是js的方法名,是相对于全局来说(​​window​​​),如果要调用​​window.some.functionA​​​,则方法名就是​​some.functionA​​。第二个参数是js方法的入参。
  2. ​JSRuntimeExtensions.InvokeVoidAsync​​:当不需要js的返回值时,使用这个。

示例:

JS方法:

<script>
window.convertArray = (win1251Array) => {
var win1251decoder = new TextDecoder('windows-1251');
var bytes = new Uint8Array(win1251Array);
var decodedArray = win1251decoder.decode(bytes);
console.log(decodedArray);
return decodedArray;
};
</script>

C#方法:

@page "/test"
@inject IJSRuntime JS

@code {
private async Task ConvertArray()
{
text = new(await JS.InvokeAsync<string>("convertArray", quoteArray));
}
}

3. JS方法调用C#方法

3.1 调用C#的静态方法

需要借助js的​​DotNet.invokeMethod​​​和​​DotNet.invokeMethodAsync​​函数,第一个参数是程序集的名称,第二个参数是静态方法的名称(或别名),第三四等是静态方法的入参。

被调用的C#方法上要使用​​[JSInvokable]​​特性。

JS方法:

returnArrayAsyncJs: function () {
DotNet.invokeMethodAsync('{APP ASSEMBLY}', 'DifferentMethodName','入参1','入参2')
.then(data => {
data.push(4);
console.log(data);
});
}

C#方法:

@code {
[JSInvokable("DifferentMethodName")]
public static Task<int[]> ReturnArrayAsync(a,b)
{
return Task.FromResult(new int[] { 1, 2, 3 });
}
}

3.2 调用C#的实例方法

我看了一遍感觉有点脱裤子放屁:c#先调用了js,然后这个js又调用了hellohelper的sayhell。js没法直接new一个hellohelper所以需要用​​DotNetObjectReference.Create​​。

  1. Razor页面:调用交互类
<button type="button" class="btn btn-primary" @onclick="TriggerNetInstanceMethod">点击</button>

@code {
public async Task TriggerNetInstanceMethod()
{
//调用交互类
await new ExampleJsInterop(JS).CallHelloHelperSayHello("Blazor");
}
}
  1. ​ExampleJsInterop.cs​​交互类:调用JS代码
public class ExampleJsInterop : IDisposable
{
private readonly IJSRuntime js;
private DotNetObjectReference<HelloHelper> objRef;
public ExampleJsInterop(IJSRuntime js)
{
this.js = js;
}
public ValueTask<string> CallHelloHelperSayHello(string name)
{
objRef = DotNetObjectReference.Create(new HelloHelper(name));
//调用JS代码
return js.InvokeAsync<string>(
"exampleJsFunctions.sayHello",
objRef);
}
public void Dispose()
{
objRef?.Dispose();
}
}
  1. JS代码:拿到从交互类传过来的​​HelloHelper​​​示例,并调用​​SayHello​​方法
window.exampleJsFunctions = {
sayHello: function (dotnetHelper) {
return dotnetHelper.invokeMethodAsync('SayHello')
.then(r => console.log(r));
}
};
  1. ​HelloHelper​​类:
public class HelloHelper
{
public HelloHelper(string name)
{
Name = name;
}

public string Name { get; set; }

[JSInvokable]
public string SayHello() => $"Hello, {Name}!";
}

3.3 调用Razor组件的实例方法

类似于静态方法的调用,需要将要调用的实例方法包装成​​Action​​。

JS代码,​​APP ASSEMBLY​​是blazor程序集的名称:

function updateMessageCallerJS() {
DotNet.invokeMethodAsync('{APP ASSEMBLY}', 'UpdateMessageCaller');
}

Razor组件:

@page "/JSInteropComponent"


@code {
private static Action action;
private string message = "Select the button.";
protected override void OnInitialized()
{
action = UpdateMessage;
}
private void UpdateMessage()
{
//这个是需要调用的实例方法
message = "UpdateMessage Called!";
StateHasChanged();
}
[JSInvokable]
public static void UpdateMessageCaller()
{
action.Invoke();
}
}

3.3.1 调用组件实例方法的一个帮助类

这个帮助类在以下两种情况下比较有用,如果不用帮助类那么会影响到同一个组件的所有实例:


  1. 组件是一个类似于Item一样的可重用组件。
  2. 使用的是blazor server应用,导致多个用户使用的是同一个组件。

帮助类如下:

using System;
using Microsoft.JSInterop;

public class MessageUpdateInvokeHelper
{
private Action action;
public MessageUpdateInvokeHelper(Action action)
{
this.action = action;
}
[JSInvokable("{APP ASSEMBLY}")]
public void UpdateMessageCaller()
{
action.Invoke();
}
}

组件代码如下:

@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@code {
private string message = "Select one of these list item buttons.";
private string display = "inline-block";
private MessageUpdateInvokeHelper messageUpdateInvokeHelper;

protected override void OnInitialized()
{
messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
}
protected async Task InteropCall()
{
await JS.InvokeVoidAsync("updateMessageCallerJS",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}

(每次new了一个新组件,也会new一个帮助类)

JS代码如下:

window.updateMessageCallerJS = (dotnetHelper) => {
dotnetHelper.invokeMethodAsync('{APP ASSEMBLY}', 'UpdateMessageCaller');
dotnetHelper.dispose();
}