1.环境

VS2019 16.5.1

.NET Core SDK 3.1.200

Blazor WebAssembly Templates 3.2.0-preview2.20160.5

2.前言

Blazor的存在可以让我们再前端以高性能运行代码,但是有些时候我们不得不需要使用JS来进行一些操作,尤其是在使用第三方JS库的时候,而在JS执行完毕后,可能还需要JS通知C#执行的结果,这时候就需要使用C#调用JS或者是JS调用C#。

3.C#调用JS

3.1.函数定义

C#调用JS是通过IJSRuntime来实现的。IJSRuntime定义了两个方法(当然,这两个方法都有重载,但是这两个方法是常见的):

ValueTask<TValue> InvokeAsync<TValue>(string identifier, object[] args);
ValueTask InvokeVoidAsync<TValue>(string identifier, object[] args);

InvokeAsync和InvokeVoidAsync的定义类似,形参identifier代表要执行的js函数名(要求必须挂载在window对象上),可以为JSON格式的标识,args则是js函数所需要的参数。其中,InvokeAsync用于执行有返回值的js函数,InvokeVoidAsync用于执行无返回值的js函数,这是两者的区别。

我们可以看到,IJSRuntime中的这两个函数都是异步函数,这是因为如果Blazor是服务端渲染的格式,其使用SignalR进行交互,JS互操作调用都必须是异步的。如果我们希望在WebAssembly应用程序(客户端渲染)下同步调用js函数,则可以将IJSRuntime对象转换为IJSInProcessRuntime对象,IJSInProcessRuntime对象中定义了一个同步方法Invoke,其形参与上述的两个相同。

T Invoke<T>(string identifier, params object[] args)

注意:IJSRuntime在Server与Client渲染模式中都可以使用,IJSInProcessRuntime只可在Client渲染模式中使用。

3.2.IJSRuntime的注入

如果我们直接在razor组件中使用IJSRuntime对象,则可以通过@inject指令将IJSRuntime对象注入到组件中;如果我们需要在类中调用IJSRuntime对象,则需要使用Inject属性注解进行注入:

//组件中注入
@inject IJSRuntime JsRuntime
//类中注入
[Inject]
public IJSRuntime JsRuntime { get; set; }

3.3.使用

新建一个Blazor WebAssembly应用程序,打开Index.razor页面,在路由属性下插入以下代码:

@inject IJSRuntime JsRuntime
<div class="jumbotron bg-white border border-primary">
<h5>C#与JS互操作</h5>
<div>
<button @onclick="OnClick" class="btn btn-primary">交互</button>
</div>
</div>

在这里定义了一个button,并为它添加了onclick事件,注意我们在为HTML的原生事件添加绑定时,需要在事件前添加“@”符号。接下来,我们实现OnClick事件响应函数。OnClick函数的返回结果可以是Task,也可以为void,此外,还可以有一个事件参数(像js中定义事件函数一样,可以不用写e)。OnClick的定义如下:

private async Task OnClick(MouseEventArgs e)
{
Console.WriteLine("OnClick is executing");
var name = "world";
var a = ;
var b = ;
var jsRunResult = await JsRuntime.InvokeAsync<string>("interop.runJs", name, a, b);
Console.WriteLine($"interop.runJs return:{jsRunResult}");
}

在OnClick中使用JsRuntime调用了一个js函数runJs。runJs可以通过window.interop.runJs被调用。interop.runJs的定义如下(为了区分C# Console.WriteLine的输出,这里使用console.warn,使两者具备不同的背景色):

window.interop = {
runJs: (name, a, b) => {
console.warn("runJs is executing");
console.warn("hello " + name);
return "OK " + (a + b);
}
}

点击“交互”按钮,浏览器中控制台的输出结果如下(WASM: 是C#Console.WriteLine默认输出的前缀):

4.JS调用C#

从JS调用C#有两种方式,一种是调用静态方法,另外一种是调用实例方法,无论那种方式,C#中能被JS调用的函数都需要标注JSInvokable属性注解。

4.1.静态方法的调用

4.1.1.介绍

静态方法的调用是通过DotNet.invokeMethod或DotNet.invokeMethodAsync来实现的:

DotNet.invokeMethod("程序集的名称", "静态方法名称",参数1,…,参数n);

DotNet.invokeMethodAsync定义与DotNet.invokeMethod定义相似,两者区别在于DotNet.invokeMethodAsync的返回值为Promise,DotNet.invokeMethod结果就是函数的返回值。

4.1.2.实例

首先,我们在Index页面中定义一个静态函数Sum:

[JSInvokable]
public static Task<int> Sum(int a, int b)
{
Console.WriteLine("Sum is executing");
return Task.FromResult(a + b);
}

Sum的作用就是将用于替换runJs中放入求和。

然后我们添加一个runCsharp JS函数,并修改runJs的返回值为”return "OK " + runCsharp(a, b);“。runCsharp的定义如下:

const runCsharp = (a, b) => {
console.warn("runCsharp is executing");
//invokeResult是Task序列化的结果
let invokeResult = DotNet.invokeMethod("BlazorInterop", "Sum", a, b);
if (invokeResult.isCompletedSuccessfully) {
return invokeResult.result;
}
return -1;
};

点击“交互”按钮,浏览器中控制台的输出结果如下:

注意:由于Sum的返回值为Task,因此其返回结果invokeResult是Task的序列化结果,通过DotNet.invokeMethodAsync(…).then(result=>)得到的result则是求和的结果。

4.2.实例方法的调用

4.2.1. 介绍

实例方法顾名思义,是指利用组件的实例调用方法,因此需要先将要执行的函数所在类的实例(可以不是组件)传递到JS中。这个实例并不是单纯的new的结果,而是使用DotNetObjectReference对new进行封装的结果:

//组件实例封装:
DotNetObjectReference.Create(this)
//类实例封装:
var classInstance = new SomClass();
DotNetObjectReference.Create(classInstance)

4.2.2.实例

首先,在Index页面中定义一个新的button,并为这个button绑定事件方法OnClick2:

<button @onclick="OnClick2" class="btn btn-primary">交互2</button>

OnClick2的定义如下:

private void OnClick2()
{
IJSInProcessRuntime SyncJsRuntime = JsRuntime as IJSInProcessRuntime;
var a = ;
var b = ;
var jsRunResult = SyncJsRuntime.Invoke<string>("interop.runJs2",DotNetObjectReference.Create(this),a, b);
Console.WriteLine($"interop.runJs2 return:{jsRunResult}");
}

OnClick2中使用IJSInProcessRuntime同步调用了一个JS函数runJs2:

runJs2: (objInstance, a, b) => {
let invokeResult = objInstance.invokeMethod("Multiply", a, b);
console.warn(invokeResult);
return "OK:" + invokeResult;
}

runJs2有三个参数:对象实例、a、b,然后通过对象实例调用了Index组件中的一个Multiply函数对a、b进行求积。Multiply函数定义如下:

[JSInvokable]
public int Multiply(int a, int b)
{
Console.WriteLine("Multiply is executing");
return a * b;
}

点击“交互2”按钮,浏览器中控制台的输出结果如下:

代码:https://github.com/zxyao145/LearningBlazor/tree/master/BlazorInterop

本文参考:

从ASP.NET Core Blazor中的.NET方法调用JavaScript函数

从ASP.NET Core Blazor中的JavaScript函数调用.NET方法

Blazor入门笔记(3)-C#与JS交互的更多相关文章

  1. Blazor入门笔记(6)-组件间通信

    1.环境 VS2019 16.5.1.NET Core SDK 3.1.200Blazor WebAssembly Templates 3.2.0-preview2.20160.5 2.简介 在使用B ...

  2. Blazor入门笔记(5)-数据绑定

    1.环境 VS2019 16.5.1 .NET Core SDK 3.1.200 Blazor WebAssembly Templates 3.2.0-preview2.20160.5 2.默认绑定 ...

  3. Blazor入门笔记(4)-组件的生命周期

    1.环境 VS2019 16.5.1.NET Core SDK 3.1.200Blazor WebAssembly Templates 3.2.0-preview2.20160.5 2.简介 Blaz ...

  4. Blazor入门笔记(2)-分部类组件与组件的继承

    1.前言 本文接自Blazor的组件(1)-从0构建一个组件 2.分部类组件 Razor组件你可理解为就是一个类名与文件名相同的类,因此,可以新建一个同名的partial类,将组件中@code里面的代 ...

  5. Blazor入门笔记(1)-从0构建一个组件

    1.环境 VS2019 16.5.1 .NET Core SDK 3.1.200 Blazor WebAssembly Templates 3.2.0-preview2.20160.5 2.创建项目 ...

  6. React.js入门笔记

    # React.js入门笔记 核心提示 这是本人学习react.js的第一篇入门笔记,估计也会是该系列涵盖内容最多的笔记,主要内容来自英文官方文档的快速上手部分和阮一峰博客教程.当然,还有我自己尝试的 ...

  7. 每天成长一点---WEB前端学习入门笔记

    WEB前端学习入门笔记 从今天开始,本人就要学习WEB前端了. 经过老师的建议,说到他每天都会记录下来新的知识点,每天都是在围绕着这些问题来度过,很有必要每天抽出半个小时来写一个知识总结,及时对一天工 ...

  8. Linux 入门笔记

    一开始对linux总有些抵触,黑黑的命令框不知道如何下手,这次因为工作交接的缘故需要负责之前同事的Node后端部分,node,redis这些都是部署在Linux上的,看了几次运维的同学噼里啪啦的敲命令 ...

  9. WebView JS交互 JSBridge 案例 原理 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

随机推荐

  1. 【字节校招】【实习】【内推】字节跳动春招(校招或实习均可)以及日常实习内推ing

    本人是年前刚刚入职抖音的应届生,职业认证还未来的级更改,但是这些都不重要.重要的是我们不能错过优秀的你~ 字节跳动的相关福利我就不介绍了,技术实习生是400/天,房补是1500/月,三餐免费,下午茶, ...

  2. docker 技术全面整理

    docker 和 vm 虚拟机技术比较像,但又有一些区别. vm 像真机一样有 BIOS ,有硬盘,有网卡,声卡,可以安装操作系统, win7 win10 macOS ubuntu centOS,有好 ...

  3. ASP.NET Core ActionFilter引发的一个EF异常

    最近在使用ASP.NET Core的时候出现了一个奇怪的问题.在一个Controller上使用了一个ActionFilter之后经常出现EF报错. InvalidOperationException: ...

  4. Flask 请求中间件、错误处理、标签、过滤器、CBV

    目录 一.请求中间件 二.请求中间件额外方法(重写源码) 三.请求错误处理 四.请求标签.过滤器 五.CBV写法 基础版 常用版 一.请求中间件 中间件: 1 before_first_request ...

  5. 使用express+shell在服务器上搭建一套简单的前端部署系统

    前言 个人项目越来越多,部署需要频繁操作服务器,所以手动搭建一套简单的部署系统. 效果如图 其中包含 原生html+css+js项目,单页面react, vue, angular项目,实现了一键打包发 ...

  6. [BUG]document.body.scrollTop=0不生效(回到顶部)

    描述 让body回滚到最顶部,设置 document.body.scrollTop = 0; . 微信内,安卓设备可以,ios设备不可以.   原因 MDN中 scrollTop是这样定义的 一个元素 ...

  7. tensorflow一些API的基本理解

    1.tf.Session self._session = None opts = tf_session.TF_NewSessionOptions(target=self._target, config ...

  8. Redis源码分析: String(SDS)容量调整分析

    整体思路: 1 惰性缩容.不释放空间,留给到期释放等机制释放. 2 加倍扩容.在需要空间达1M之前按新空间两倍分配空间,否则按新空间大小+1M分配.注意,1M=1024*1024*Char.Char可 ...

  9. 加油站问题 Gas Station

    2019-06-01 17:09:30 问题描述: 问题求解: 其实本题本质上是一个数学题. [定理] 对于一个循环数组,如果这个数组整体和 SUM >= 0,那么必然可以在数组中找到这么一个元 ...

  10. ASP.NET Core 奇淫技巧之伪属性注入

    一.前言 开局先唠嗑一下,许久未曾更新博客,一直在调整自己的状态,去年是我的本命年,或许是应验了本命年的多灾多难,过得十分不顺,不论是生活上还是工作上.还好当我度过了所谓的本命年后,许多事情都在慢慢变 ...