如何在 Blazor 中执行客户端 UI 事件

How to do client-side UI events in Blazor

我刚刚开始使用 Blazor,我已经可以看到这个新框架的巨大潜力。

不过,我想知道它将如何处理简单的事情,例如将焦点设置在输入控件上?例如,在我处理了一个点击事件之后,我想将焦点设置到一个文本输入控件上。我是否必须使用 JQuery 来处理类似的事情,或者 Blazor 是否会为此类事情提供一些内置方法?

谢谢

更新:我在下面发布了一个答案,其中包含一个示例,说明如何通过从 .Net 代码调用 JavaScript 函数来将焦点设置到控件上。

截至目前(Blazor 0.9.0),您在 Index.html 中创建 JavaScript 函数(或从 Index.html 中引用它们),然后在您的 Blazor 页面或组件中你打电话给 JsRuntime.InvokeAsync("functionName", parms);

https://docs.microsoft.com/en-us/aspnet/core/razor-components/javascript-interop

Blazor 只是 JavaScript 的替代品(更准确地说是“增值”)。这是一个仅 client-side 的解决方案(但它可能会在将来添加一些简单的绑定到 ASP.NET)。

不过,它完全基于 HTML 和 CSS。 C# 正在使用 Web 程序集替换 JS 部分。因此,您访问/修改 HTML 控件的方式没有任何变化。

截至目前(版本 0.1.0)你必须依赖 HTML DOM focus() 方法来做你想做的事(是的你必须使用 JavaScript 截至目前 :( ).

// Not tested code
// This is JavaScript. 
// Put this inside the index.html. Just below <script type="blazor-boot"></script>
<script>
    Blazor.registerFunction('Focus', (controlId) => {
      return document.getElementById(controlId).focus();
    });
</script>

//and then wrap it for calls from .NET:    
// This is C#

public static object Focus(string controlId)
{
    return RegisteredFunction.Invoke<object>("Focus", controlId);
    //object type is used since Invoke does not have a overload for void methods. Don't know why. 
    //this will return undefined according to js specs
}

更多信息,您可以参考下文

如果你想把JS包装的更整齐,你可以这样做:

public class BlazorExtensionScripts : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
{
    protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
    {
        builder.OpenElement(0, "script");
        builder.AddContent(1, "Blazor.registerFunction('Focus', (controlId) => { document.getElementById(controlId).focus(); });");
        builder.CloseElement();
    }

    public static void Focus(string controlId)
    {
        RegisteredFunction.Invoke<object>("Focus", controlId);
    }
}

然后将此组件添加到根:(App.cshtml):

<BlazorExtensionScripts></BlazorExtensionScripts>
<Router AppAssembly=typeof(Program).Assembly />

不能直接调用JavaScript函数。您需要先注册您的功能,例如

<script>
 Blazor.registerFunction('ShowControl', (item) => {       
     var txtInput = document.getElementById("txtValue");         
     txtInput.style.display = "";
     txtInput.value = item;
     txtInput.focus();          
});
return true;
</script>

然后您需要在 C# 中声明一个调用此 JavaScript 函数的方法。喜欢,

private void CallJavaScript()
{
   RegisteredFunction.Invoke<bool>("ShowControl", itemName);
}

您可以在单击按钮时调用此 C# 方法。喜欢,

<button id="btnShow" class="btn btn-primary" @onclick(CallJavaScript)>Show</button>

这个postCreate a CRUD App using Blazor and ASP.NET Core 显示了从 Blazor 调用 JavaScript 的工作演示。

我想添加一个更新的(自 0.9.0 起)示例,​​该示例调用 JavaScript 函数以在某些事件(例如单击按钮)后将焦点设置到另一个控件。这可能对刚开始使用 Blazor 的人(比如我)有帮助。

此示例基于位于 https://docs.microsoft.com/en-us/aspnet/core/tutorials/build-your-first-razor-components-app?view=aspnetcore-3.0

的 Blazor 文档 "Build Your First Blazor Components App" 中的示例代码

首先,按照文档中的所有说明进行操作。当您有一个可用的待办事项列表页面时,请添加以下内容:

  1. 在 Index.html 的底部,wwwroot 下,加载 webassembly.js 的脚本标签下方,添加以下脚本:
<script>
        window.MySetFocus = (ctrl) => {
            document.getElementById(ctrl).focus();
            return true;
        }
</script>
  1. 在您的 todo.cshtml 页面顶部,添加以下 using 语句:
@inject IJSRuntime JsRuntime;
  1. 在 todo.cshtml 页面的 @functions 部分,添加以下函数:
    async void Focus(string controlId)
    {
        var obj = JsRuntime.InvokeAsync<string>(
            "MySetFocus", controlId);
    }

  1. 在 AddToDo() 函数中,就在您将 "newToDo" 变量设置为空字符串的行下方,添加对 Focus 函数的调用,并传入输入控件的字符串 ID。 (文档中的例子没有给input控件分配ID,所以自己加一个吧,我的是"todoItem")。

void AddTodo()
    {
        if (!string.IsNullOrWhiteSpace(newTodo))
        {
            todos.Add(new TodoItem { Title = newTodo });
            newTodo = string.Empty;
            Focus("todoItem"); // this is the new code
        }
    }

  1. 构建并 运行 您的应用。当您单击添加新项目按钮时,新项目应该被添加到列表中,输入控件消失,焦点应该回到输入控件中,准备添加另一个项目。

来自 .NET 5 预览版 8

Set UI focus in Blazor apps

Blazor 现在在 ElementReference 上有一个 FocusAsync 便捷方法,用于在该元素上设置 UI 焦点。

<button @onclick="() => textInput.FocusAsync()">Set focus</button>
<input @ref="textInput"/>