Blazor学习之旅 (12) JS与Blazor的互操作

d3239b536fd18f8ae15970ad35ff1dd1.jpeg

【Blazor】| 总结/Edison Zhou


大家好,我是Edison。

很久没有更新Blazor这个系列了,在上一篇我们学习了Blazor+SignalR开发简单的实时应用程序,这一篇我们了解下Blazor和JavaScript的互操作性。

有了Blazor还需要JavaScript?

我们都知道,在Blazor中我们可以轻松地使用C#组件而不是JavaScript来创建Web应用程序,但是,这并不代表我们不能继续使用JavaScript提供的便利。

很多时候,我们可能希望继续使用JavaScript提供的函数来实现某些功能,这时,我们可以用Blazor和JavaScript的互操作性(也称为JS互操作)来调用Blazor应用中的JavaScript库,并从C#代码直接调用JavaScript函数。当然,也可以使用JS互操作性从JavaScript函数调用C#方法。

这种场景经常发生在:有时候需要使用现有的JavaScript库,例如一些开源JavaScript库以专门的方式呈现组件和处理用户界面元素,又或者你可能拥有一些开源JavaScript库的开发调试经验,是个JavaScript库的老鸟了,你希望重用该JavaScript代码而不是将其转换为C#。那么,这个时候,你可能就需要用上JS互操作性了。

接下来,我们就来看看如何在Blazor应用中加载JavaScript代码,又如何在JavaScript中调用.NET代码。

在Blazor中调用JavaScript代码

(1)加载方式

将JavaScript添加到Blazor应用的方式与添加到标准HTML Web应用一样,都是使用HTML的<script>元素。我们可以在 Pages/_Layout.cshtml 文件或 wwwroot/index.html文件中的现有 <script src="_framework/blazor.*.js"></script> 标记后添加 <script> 标记即可。

NOTE:最好不要将JavaScript脚本放在页面的<head>元素中。

将JavaScript库或脚本添加之后,我们就可以在C#代码中通过使用 IJSRuntime 接口调用JavaScript函数了。不过,你需要提前将 IJSRuntime 实例注入Blazor页面中。

IJSRuntime 接口用于调用JavaScript代码的 InvokeAsync(有返回值) 和 InvokeVoidAsync(无返回值) 两个方法。顾名思义,这两个方法都是异步的,因此你需要在使用时标注await来获取结果。

InvokeAsync 或 InvokeVoidAsync 方法的接收参数,第一个是要调用的JavaScript函数的名称,比如 confirm 这个方法名。第二个则是这个函数所需的任何参数。

需要注意的是:

  • JavaScript函数必须属于 window 作用域 或 window 子作用域;

  • 传入的参数必须是可序列化为JSON的;

(2)DEMO

假设我们已经有了一个Blazor Server应用程序,你可以从这里获取Code:https://github.com/Coder-EdisonZhou/BlazorSamples。

这里我们改写一下经典的Counter页面,将原来的按钮直接加一改为调用JavaScript的confirm函数弹出一个确认框,确认后再加一。

为了实现这个功能,我们需要改写如下:

Step1. 注入IJSRuntime抽象实例

[Inject]
public IJSRuntime JavaScript { get; set; }

Step2. 改写原来的button按钮调用IncrementCountConfirmation方法

@* <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> *@
<button class="btn btn-primary" @onclick="@(async() => await IncrementCountConfirmation())">Click me</button>

Step3. 实现IncrementCountConfirmation方法

@code {
    private int currentCount = 0;


    [Parameter]
    public int IncrementAmount { get; set; } = 1;


    [Inject]
    public IJSRuntime JavaScript { get; set; }


    private void IncrementCount()
    {
        currentCount += IncrementAmount;
    }
    
    private async Task IncrementCountConfirmation()
    {
        if (await JavaScript.InvokeAsync<bool>(
          "confirm", 
          "Do you want to increment the count?"))
        {
            currentCount += IncrementAmount;
        }
    }
}

最终的效果如下图:

4264166abe80cfff8dd48ab44b6083ea.gif

那么,如果想要使用第三方JavaScript库的函数该如何做呢?

你只需要在 Pages/_Layout.cshtml 文件的末尾,在现有 <script src="_framework/blazor.*.js"></script> 标记后添加你需要引入的JavaScript库即可。

然后,你就可以在C#代码中继续通过 IJSRuntime 调用第三方JavaScript库中的函数了。

在JavaScript中调用C#代码

(1)加载方式

在JavaScript中若想调用C#代码可以使用 DotNet实用工具类(JS互操作的一部分)来运行Blazor代码中定义的.NET方法。在这个工具类中提供了 invokeMethod 和 invokeMethodAsync 两个函数,顾名思义,一个是同步的,另一个是异步的。

invokeMethodAsync方法返回 JavaScript Promise。

需要注意的是:

  • 要调用的.NET方法需要使用 JSInvokableAttribute 标记

  • 且该方法必须是 public的

  • 且该方法任何参数都必须可序列化为JSON

(2)DEMO

假设我们已经有了一个Blazor Server应用程序,你可以从这里获取Code:https://github.com/Coder-EdisonZhou/BlazorSamples。

这里我们改写一下经典的Counter页面,增加一个button用于在JavaScript中调用.NET静态方法。

Step1. 添加HTML与JavaScript

<h1>Call .NET Example From JavaScript</h1>


<p>
    <button onclick="returnArrayAsync()">
        Trigger .NET static method
    </button>
</p>


<script>
    window.returnArrayAsync = () => {
        DotNet.invokeMethodAsync('EDT.BlazorServer.App', 'ReturnArrayAsync')
            .then(data => {
                console.log(data);
            });
    };
</script>

Step2. 添加.NET方法并标注 JSInvokable

[JSInvokable]
public static Task<int[]> ReturnArrayAsync()
{
   return Task.FromResult(new int[] { 1, 2, 3 });
}

最终的效果如下图:

dfc41a12ba0609d8d3a55b3091786e4d.gif

那么,如果是.NET实例方法,该如何调用呢?这个就稍微复杂一丢丢了。

还是来个demo吧:

Step1. 添加HTML和JavaScript示例:

<h1>Call .NET Example From JavaScript - Sample 2</h1>


<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>


<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>


<p>
    @result
</p>


<script>
    window.sayHello = (dotNetHelper) => {
        return dotNetHelper.invokeMethodAsync('GetHelloMessage');
    };
</script>

Step2. 添加.NET方法并标注 JSInvokable,还需要声明一个 DotNetObjectReference对象便于进行资源释放,以免引起内存泄露等问题(DotNetObjectReference内部机制会主动调用Dispose方法进行释放);

@code {    
    [Inject]
    public IJSRuntime JavaScript { get; set; }


    private string? name;
    private string? result;
    private DotNetObjectReference<Counter>? objRef;


    protected override void OnInitialized()
    {
        objRef = DotNetObjectReference.Create(this);
    }


    public async Task TriggerDotNetInstanceMethod()
    {
        result = await JavaScript.InvokeAsync<string>("sayHello", objRef);
    }


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


    public void Dispose()
    {
        objRef?.Dispose();
    }
}

最终的效果如下图:

97844ddda26dafd1b173cec246899c68.gif

小结

本篇,我们了解了什么是Blazor中的JS互操作,并通过两个DEMO了解了如何在Blazor中加载JavaScript代码 以及 如何在JavaScript中调用.NET代码,相信对你会有所帮助。

参考代码

GitHub:https://github.com/EdisonChou/BlazorSamples/tree/main

43c75a21ec3d857dda80438a75956826.gif

年终总结:Edison的2022年终总结

数字化转型:我在传统企业做数字化转型

C#刷题:C#刷剑指Offer算法题系列文章目录

.NET面试:.NET开发面试知识体系

.NET大会:2020年中国.NET开发者大会PDF资料

08ab81350ebe11301781b241068fd8a4.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值