光明践行者 發表於 2020-6-12 14:37:00

ASP.NET Core Blazor WebAssembly 之 .NET JavaScript互调

<p>Blazor WebAssembly可以在浏览器上跑C#代码,但是很多时候显然还是需要跟JavaScript打交道。比如操作dom,当然跟angular、vue一样不提倡直接操作dom;比如浏览器的后退导航。反之JavaScript也有可能需要调用C#代码来实现一些功能,毕竟客户的需求是千变万化的,有的时候只能通过一些hack的手段来实现。</p>
<h2 id="net调用javascript函数">.NET调用JavaScript函数</h2>
<h3 id="使用jsruntimeinvokevoidasync调用无返回值的javascript函数">使用JSRuntime.InvokeVoidAsync调用无返回值的JavaScript函数</h3>
<p>显然我们的.NET类库里不会有JavaScript内置的alert方法来显示提示,这里演示下如何调用JavaScript的alert方法:</p>
<pre><code>&lt;h3&gt;.net call javascript&lt;/h3&gt;

&lt;button @onclick="CallJs"&gt;
    Call alert
&lt;/button&gt;

@inject IJSRuntime jsRuntime
@code {
    private void CallJs()
    {
      jsRuntime.InvokeVoidAsync("alert", "this message from .net runtime .");
    }
}

</code></pre>
<p><img src="https://s1.ax1x.com/2020/06/11/tqmG2F.gif" alt="" loading="lazy"></p>
<h3 id="使用jsruntimeinvokevoidasync调用具有返回值的javascript函数">使用JSRuntime.InvokeVoidAsync调用具有返回值的JavaScript函数</h3>
<p>我们在JavaScript环境定义一个加法函数然后.NET这边调用拿到结果:</p>
<pre><code>    &lt;script&gt;
      function add(a, b) {
            return a + b;
      }
    &lt;/script&gt;
</code></pre>
<blockquote>
<p>注意:JavaScript代码要放到wwwroot/index.html页面上里,不能直接放在组件里。</p>
</blockquote>
<p>组件代码:</p>
<pre><code>&lt;h3&gt;.net call javascript&lt;/h3&gt;

sum: @sum

&lt;button @onclick="CallJs"&gt;
    Call Add
&lt;/button&gt;

@inject IJSRuntime jsRuntime
@code {

    private int sum = 0;

    private async void CallJs()
    {
      sum = await jsRuntime.InvokeAsync&lt;int&gt;("add", sum, 2);
      this.StateHasChanged();
    }
}

</code></pre>
<p>运行一下:</p>
<p><img src="https://s1.ax1x.com/2020/06/12/tLBLt0.gif" alt="" loading="lazy"></p>
<h2 id="javascript调用net方法">JavaScript调用.NET方法</h2>
<h3 id="javascript调用net静态方法">JavaScript调用.NET静态方法</h3>
<p>JavaScript调用.NET静态方法比较简单,把静态方法加上,然后在JavaScript环境使用DotNet对象直接call就行:<br>
定义.NET静态方法:</p>
<pre><code>
   
    public static string GetNow()
    {
      return DateTime.Now.ToString();
    }
</code></pre>
<p>使用JavaScript调用GetNow:</p>
<pre><code>$(document).ready(
            setTimeout(() =&gt; {
                $('#btn1').on('click', function () {
                  DotNet.invokeMethodAsync('BlazorWasmComponent', 'GetNow')
                        .then(data =&gt; {
                            alert(data);
                        });
                })
            }, 10000)
      );
</code></pre>
<p>由于Blazor渲染UI结束后按钮才会插入到dom树上,所以这里使用一个傻办法让绑定事件的JavaScript代码置后运行。<br>
运行一下:<br>
<img src="https://s1.ax1x.com/2020/06/12/tLxZnO.gif" alt="" loading="lazy"></p>
<h3 id="javascript调用组件里的方法">JavaScript调用组件里的方法</h3>
<p>JavaScript调用组件里的方法比较绕,其实还是通过一个静态方法作为入口,把实例方法绑定一个静态delegate,然后让这个静态方法去执行delegate。<br>
.NET代码:</p>
<pre><code>&lt;h3&gt;javascript call .net&lt;/h3&gt;

&lt;button id="btn1"&gt;
   Js call .net
&lt;/button&gt;

@inject IJSRuntime jsRuntime
@code {

   
    public static string GetNow()
    {
      return Act("");
    }

    public static Func&lt;string, string&gt; Act;

    protected override void OnInitialized()
    {
      Act = GetNowInInstance;
      base.OnInitialized();
    }

    public string GetNowInInstance(string str)
    {
      return DateTime.Now.ToString();
    }
}

</code></pre>
<p>JavaScript代码:</p>
<pre><code> $(document).ready(
            setTimeout(() =&gt; {
                $('#btn1').on('click', function () {
                  DotNet.invokeMethodAsync('BlazorWasmComponent', 'GetNow')
                        .then(data =&gt; {
                            alert(data);
                        });
                })
            }, 10000)
      );
</code></pre>
<p>运行一下:<br>
<img src="https://s1.ax1x.com/2020/06/12/tLxZnO.gif" alt="" loading="lazy"></p>
<h3 id="调用对象的方法">调用对象的方法</h3>
<p>Blazor还可以把.NET对象(引用)直接传递到JavaScript运行时来让JavaScript直接调用.NET对象的方法。</p>
<p>总的来说大概分4步:</p>
<ol>
<li>实例化.net对象</li>
<li>DotNetObjectReference.Create方法把.NET对象包装</li>
<li>通过JSRuntime调用一个JavaScript方法把第二步生成的对象传递到JavaScript运行时</li>
<li>在JavaScript侧通过invokeMethodAsync方法调用.NET对象里的方法</li>
</ol>
<p>下面演示下把组件整个实例传递出去,然后调用里面的GetNowInInstance方法。</p>
<p>.net代码:</p>
<pre><code>&lt;h3&gt;javascript call .net&lt;/h3&gt;

&lt;button id="btn1"&gt;
    Js call .net
&lt;/button&gt;
@implements IDisposable
@inject IJSRuntime jsRuntime
@code {
    IDisposable _objRef;
    protected async override Task OnInitializedAsync()
    {
      _objRef = DotNetObjectReference.Create(this);
      await jsRuntime.InvokeAsync&lt;string&gt;(
            "receiveNetObj",
         _objRef);
      base.OnInitialized();
    }

   
    public string GetNowInInstance()
    {
      return DateTime.Now.ToString();
    }

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

</code></pre>
<blockquote>
<p>注意:把.NET对象传递到JavaScript运行时存在内存泄漏的风险,所以组件需要实现IDisposable接口,在Dispose方法内调用objRef的Dispose方法来释放内存。</p>
</blockquote>
<p>JavaScript代码:</p>
<pre><code>      var _netObj = null;

      function receiveNetObj(obj) {
            _netObj = obj;
      }

      $(document).ready(
            setTimeout(() =&gt; {
                $('#btn1').on('click', function () {
                  _netObj.invokeMethodAsync("GetNowInInstance").then(
                        r =&gt; alert(r)
                  );
                })
            }, 10000)
      );
</code></pre>
<p>运行一下:<br>
<img src="https://s1.ax1x.com/2020/06/12/tLxZnO.gif" alt="" loading="lazy"></p>
<h2 id="总结">总结</h2>
<p>使用JSRuntime可以在.NET里调用JavaScript的方法,这些方法必须是全局的,也就是挂载在window对象上的。<br>
在JavaScript里调用.NET方法主要有两种:</p>
<ol>
<li>通过DotNet方式调用.NET的静态方法</li>
<li>把.NET对象直接传递到JavaScript运行时来调用对象上的方法</li>
</ol>
<p>相关内容</p>
<p>ASP.NET Core Blazor Webassembly 之 路由<br>
ASP.NET Core Blazor Webassembly 之 数据绑定<br>
ASP.NET Core Blazor Webassembly 之 组件<br>
ASP.NET Core Blazor 初探之 Blazor WebAssembly<br>
ASP.NET Core Blazor 初探之 Blazor Server</p>
<p>关注我的公众号一起玩转技术<br>
<img src="https://s1.ax1x.com/2020/06/29/NfQjds.jpg" alt="" loading="lazy"></p>


</div>
<div id="MySignature" role="contentinfo">
    <div id="AllanboltSignature">      
<p id="PSignature" style="border-top: #e0e0e0 1px dashed; border-right: #e0e0e0 1px dashed; border-bottom: #e0e0e0 1px dashed; border-left: #e0e0e0 1px dashed; padding-top: 10px; padding-right: 10px; padding-bottom: 10px; padding-left: 10px; font-family: 微软雅黑; font-size: 11px">      
QQ群:1022985150 VX:kklldog 一起探讨学习.NET技术
<br>
作者:Agile.Zhou(kklldog)            
<br>
出处:http://www.cnblogs.com/kklldog/
<br>本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
</p>
</div><br><br>
来源:https://www.cnblogs.com/kklldog/p/blazor-wasm-jsnetcall.html
頁: [1]
查看完整版本: ASP.NET Core Blazor WebAssembly 之 .NET JavaScript互调