前言:
虽然BlazorServer中推荐使用C#在razor页面中的替代JavaScript来完成逻辑的编写,但当需要使用第三方的javascript文件/组件里的内容时,则难免要在C#中调用其方法或对象。反之当你的(用到第三方组件的)Javascript代码想要和后台交互时,则需要调用C#的代码。好在BlazorServer中这两种通信都是支持的。下面将介绍其具体的实现方式。
Blazor提供了IJSRuntime组件来提供与JavaScript的交互。
BlazorServer启动时就已经创建了IJSRuntime的实例,所以你可以直接使用构造方法注入
public class CustomService
{
private readonly IJSRuntime _runtime;
public CustomService(IJSRuntime runtime)
{
_runtime = runtime;
}
}
在razor页面(组件)中也是直接获取即可
page "/mytest"
<!--直接使用@inject标签获取即可-->
@inject IJSRuntime runtime
<h3>MyTest</h3>
page "/mytest"
<!--直接使用@inject标签获取即可-->
@inject IJSRuntime runtime
<h3>MyTest</h3>
<button type="button" @onclick="DoNothing">点击</button>
@code {
public void DoNothing()
{
await runtime.InvokeVoidAsync("alert",new object[1] { "FUCKYOU" }); //无返回值
//runtime.InvokeAsync<>(); 有返回值
}
}
测试结果:
上面的只单独调用公共函数的时候不多,大多数时候需要从别的地方获取。调用方法如下
现有一自定义js文件如下(TestScript.js)
function WhatTheHell() {
alert("WTF");
}
function WhatTheHell_2() {
alert("这次有返回值");
return 123
}
function WhatTheHell_3(param) {
alert("有返回值及参数");
console.log(JSON.stringify(param));
return 10086
}
先将其放到BlazorServer的js文件指定目录下(wwwroot/js/)
再在_Host.cshtml中引入该js文件
在razor页面中使用
@page "/mytest"
@inject IJSRuntime runtime
<h3>MyTest</h3>
<button type="button" @onclick="MethodOne">方法一(无返回值和参数)</button> <br/>
<button type="button" @onclick="MethodTwo">方法二(无返回值)</button> <br/>
<button type="button" @onclick="MethodThree">方法三(返回值和参数)</button> <br/>
@code {
public async void MethodOne()
{
await runtime.InvokeVoidAsync("WhatTheHell",null);
}
public async void MethodTwo()
{
var num = await runtime.InvokeAsync<int>("WhatTheHell_2",null);
Console.WriteLine("获取js的返回值为" + num);
}
public async void MethodThree()
{
var num = await runtime.InvokeAsync<int>("WhatTheHell_3", new object[1] { "尼哥" });
Console.WriteLine("获取js的返回值为" + num);
}
}
测试结果为:
当JS的返回值为复杂对象时,则推荐使用IJSObjectReference来获取,具体可以参考
IJSObjectReference 接口 (Microsoft.JSInterop) | Microsoft Learn
在JavaScript中调用C#的方法则比较复杂,需要考虑到静态/动态区分的问题
DotNet.invokeMethodAsync('AssemblyName', 'Namespace.ClassName', 'MethodName', arg1, arg2);
这将调用指定程序集(AssemblyName)、命名空间(Namespace[可以省略])和类名(ClassName)中的静态方法(MethodName),并传递arg1和arg2作为参数。
例:
@page "/jstest"
@inject IJSRuntime runtime
<h3>Jsusecsharp</h3>
<span style="font-size:36px">到达世界最高城 @Title</span>
<button type="button" @onclick="Change">前往朝圣</button>
@code {
public static string Title = "沈阳!";
public async void Change()
{
await runtime.InvokeVoidAsync("use_csharp",null);
}
[JSInvokable]
public static void ChangeTheTitle()
{
Title = "理塘";
}
}
js文件
async function use_csharp() {
await DotNet.invokeMethodAsync('BlazorApp2','ChangeTheTitle', null);
}
测试结果:
下面是微软文档的内容
若要从 JavaScript (JS) 调用实例 .NET 方法,请执行以下操作:
通过将实例包装在 DotNetObjectReference 中并对其调用 Create,将 .NET 实例通过引用传递给 JS。
使用传递的 DotNetObjectReference 中的 invokeMethodAsync
(推荐)或 invokeMethod
(仅限 Blazor WebAssembly)从 JS 调用 .NET 实例方法。 传入实例 .NET 方法的标识符以及任意自变量。 在从 JS 调用其他 .NET 方法时,也可以将 .NET 实例作为参数传递。
如下示例中:
dotNetHelper
为 DotNetObjectReference。{.NET METHOD ID}
占位符是 .NET 方法标识符。{ARGUMENTS}
占位符是要传递给该方法的以逗号分隔的可选参数,其中每个参数都必须是可执行 JSON 序列化的。⛵️ 总结:
动态方法的调用需要传递实例(使用DotNetObjectReference对象),需要在方法中设置实例参数,再由实例进行invoke操作。
例:
@page "/jstest"
@using BlazorApp2.Utils
@inject IJSRuntime runtime
<h3>Jsusecsharp</h3>
<span style="font-size:36px">到达世界最高城 @Title</span>
<button type="button" @onclick="Change">前往朝圣</button>
@code {
public static string Title = "沈阳!";
//用于传递给JS的实例
private DotNetObjectReference<Jsusecsharp> objref;
protected override void OnInitialized()
{
objref = DotNetObjectReference.Create(this);
}
public async void Change()
{
//将实例作为参数传给调用的JS
await runtime.InvokeVoidAsync("use_csharp_dy",objref);
}
///
/// 静态方法
///
[JSInvokable]
public static void ChangeTheTitle()
{
Title = "理塘";
}
[JSInvokable("ChangeTheTitle_2")]
public void ChangeTheTitle_2()
{
Title = "通辽";
}
}
JS:
async function use_csharp_dy(instance) {
//instance 即为razor中的objref,由其进行调用
await instance.invokeMethodAsync('ChangeTheTitle_2', null);
}
参数结果:
未完。。。。。