Article Directory
1. Where JavaScript methods can be placed
js methods can be in the following locations:
1.1 in head
(not recommended)
<head>
<script>
window.jsMethod = (methodParameter) => {
...
};
</script>
</head>
Why this is not recommended: If JS depends on Blazor, then interop will fail. And it may also cause the page response to be slowed down.
1.2 body
in
<body>
<script src="_framework/blazor.{webassembly|server}.js"></script>
<script>
window.jsMethod = (methodParameter) => {
...
};
</script>
</body>
1.3 Inject js after Blazor starts
First set blazor.js
the autostart
to false
. Then call Blaozr.start().then()
the method injection script.
<body>
<script src="_framework/blazor.{webassembly|server}.js"
autostart="false">
//设置为false
</script>
<script>
Blazor.start().then(function () {
var customScript = document.createElement('script');
customScript.setAttribute('src', 'scripts.js');
document.head.appendChild(customScript);
});
</script>
</body>
2. C# method calls JS method
Objects can be used IJSRuntime
to call js methods. There are:
IJSRuntime.InvokeAsync
: The first parameter is the method name of js, which is relative to the global (window
), if it is to be calledwindow.some.functionA
, the method name issome.functionA
. The second parameter is the input parameter of the js method.JSRuntimeExtensions.InvokeVoidAsync
: Use this when you don't need the return value of js.
Example:
JS method:
<script>
window.convertArray = (win1251Array) => {
var win1251decoder = new TextDecoder('windows-1251');
var bytes = new Uint8Array(win1251Array);
var decodedArray = win1251decoder.decode(bytes);
console.log(decodedArray);
return decodedArray;
};
</script>
C# method:
@page "/test"
@inject IJSRuntime JS
@code {
private async Task ConvertArray()
{
text = new(await JS.InvokeAsync<string>("convertArray", quoteArray));
}
}
3. JS method calls C# method
3.1 Call the static method of C#
You need to use js DotNet.invokeMethod
and DotNet.invokeMethodAsync
functions. The first parameter is the name of the assembly, the second parameter is the name (or alias) of the static method, and the third and fourth are the input parameters of the static method.
Attributes are used on the C# method being called [JSInvokable]
.
JS method:
returnArrayAsyncJs: function () {
DotNet.invokeMethodAsync('{APP ASSEMBLY}', 'DifferentMethodName','入参1','入参2')
.then(data => {
data.push(4);
console.log(data);
});
}
C# method:
@code {
[JSInvokable("DifferentMethodName")]
public static Task<int[]> ReturnArrayAsync(a,b)
{
return Task.FromResult(new int[] {
1, 2, 3 });
}
}
3.2 Calling the instance method of C#
The following example is from Microsoft documentation, describing how js calls the method HelloHelper
of the instance SayHello
.
I read it again and felt a little farted: c# first called js, and then this js called hellohelper's sayhell. js can't directly new a hellohelper, so it needs to be used DotNetObjectReference.Create
.
- Razor page: call interaction class
<button type="button" class="btn btn-primary" @onclick="TriggerNetInstanceMethod">点击</button>
@code {
public async Task TriggerNetInstanceMethod()
{
//调用交互类
await new ExampleJsInterop(JS).CallHelloHelperSayHello("Blazor");
}
}
ExampleJsInterop.cs
Interaction class: calling JS code
public class ExampleJsInterop : IDisposable
{
private readonly IJSRuntime js;
private DotNetObjectReference<HelloHelper> objRef;
public ExampleJsInterop(IJSRuntime js)
{
this.js = js;
}
public ValueTask<string> CallHelloHelperSayHello(string name)
{
objRef = DotNetObjectReference.Create(new HelloHelper(name));
//调用JS代码
return js.InvokeAsync<string>(
"exampleJsFunctions.sayHello",
objRef);
}
public void Dispose()
{
objRef?.Dispose();
}
}
- JS code: Get the example passed from the interactive class
HelloHelper
and callSayHello
the method
window.exampleJsFunctions = {
sayHello: function (dotnetHelper) {
return dotnetHelper.invokeMethodAsync('SayHello')
.then(r => console.log(r));
}
};
HelloHelper
kind:
public class HelloHelper
{
public HelloHelper(string name)
{
Name = name;
}
public string Name {
get; set; }
[JSInvokable]
public string SayHello() => $"Hello, {
Name}!";
}
3.3 Call the instance method of the Razor component
Similar to the call of a static method, the instance method to be called needs to be packaged Action
.
JS code, APP ASSEMBLY
is the name of the blazor assembly:
function updateMessageCallerJS() {
DotNet.invokeMethodAsync('{APP ASSEMBLY}', 'UpdateMessageCaller');
}
Razor components:
@page "/JSInteropComponent"
@code {
private static Action action;
private string message = "Select the button.";
protected override void OnInitialized()
{
action = UpdateMessage;
}
private void UpdateMessage()
{
//这个是需要调用的实例方法
message = "UpdateMessage Called!";
StateHasChanged();
}
[JSInvokable]
public static void UpdateMessageCaller()
{
action.Invoke();
}
}
3.3.1 A helper class for calling component instance methods
This helper class is useful in the following two situations. If it is not used, it will affect all instances of the same component:
- Component is a reusable component similar to Item.
- The blazor server application is used, resulting in multiple users using the same component.
The helper class is as follows:
using System;
using Microsoft.JSInterop;
public class MessageUpdateInvokeHelper
{
private Action action;
public MessageUpdateInvokeHelper(Action action)
{
this.action = action;
}
[JSInvokable("{APP ASSEMBLY}")]
public void UpdateMessageCaller()
{
action.Invoke();
}
}
The component code is as follows:
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@code {
private string message = "Select one of these list item buttons.";
private string display = "inline-block";
private MessageUpdateInvokeHelper messageUpdateInvokeHelper;
protected override void OnInitialized()
{
messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
}
protected async Task InteropCall()
{
await JS.InvokeVoidAsync("updateMessageCallerJS",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
(Every time a new component is new, a helper class will also be new)
The JS code is as follows:
window.updateMessageCallerJS = (dotnetHelper) => {
dotnetHelper.invokeMethodAsync('{APP ASSEMBLY}', 'UpdateMessageCaller');
dotnetHelper.dispose();
}