zoukankan      html  css  js  c++  java
  • Blazor入门笔记(3)-C#与JS交互

    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 = 11;
        var b = 22;
        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 = 11;
        var b = 22;
        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方法

  • 相关阅读:
    哈希表及其应用分析
    程序员常用的查找算法
    程序猿必备排序算法及其时间复杂度分析
    递归和回溯求解8皇后问题
    链表种类及其常用操作
    为什么要使用稀疏矩阵??
    微服务项目持续集成部署流程简介
    微服务项目的docker自动化部署流程
    (高考标准分)数据拟合==>多项式方程==>excel公式算成绩(标准分)
    awk用名称对应关系批量重命名
  • 原文地址:https://www.cnblogs.com/zxyao/p/12638233.html
Copyright © 2011-2022 走看看