【问题标题】:How to do client-side UI events in Blazor如何在 Blazor 中执行客户端 UI 事件
【发布时间】:2018-09-02 18:30:39
【问题描述】:

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

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

谢谢

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

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

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

【问题讨论】:

    标签: javascript c# asp.net-core blazor javascript-interop


    【解决方案1】:

    Blazor 只是 JavaScript 的替代品(更准确地说是“增值”)。它是一个仅限客户端的解决方案(但将来可能会添加一些简单的与 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 的包装做得更整齐,你可以这样做: https://stackoverflow.com/a/49521216/476609

    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 />
    

    【讨论】:

    • 这个答案现在已经过时了。请参阅上面的更新,或访问文档:docs.microsoft.com/en-us/aspnet/core/razor-components/…
    • 如果我不能直接从 C# 访问和控制 DOM,那有什么意义呢?使用这种方法,我最终会得到一个部分是 C# 和部分 Javascript 的客户端,这比全是 Javascript 的客户端还要糟糕。
    • @Neutrino 不幸的是,这通常是 WebAssembly 的问题,而不是 blazor。 WebAssembly 目前无法访问 DOM。已经讨论过添加到路线图中,但我不知道它的当前状态是什么。许多人会争辩说,在大多数情况下,您实际上并不需要访问 DOM,但这是一个完全独立的讨论。
    【解决方案2】:

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

    此示例基于 Blazor 文档“构建您的第一个 Blazor 组件应用程序”中的示例代码,地址为 https://docs.microsoft.com/en-us/aspnet/core/tutorials/build-your-first-razor-components-app?view=aspnetcore-3.0

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

    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。 (文档中的示例没有为输入控件分配 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. 构建并运行您的应用程序。当您单击添加新项目按钮时,新项目应添加到列表中,输入控件变为空白,焦点应回到输入控件中,准备添加另一个项目。

    【讨论】:

    • 对于那些从 VSCode 模板创建的,没有 index.html。请改用 _Host.cshtml。
    【解决方案3】:

    来自 .NET 5 预览版 8

    Set UI focus in Blazor apps

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

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

    【讨论】:

    • 这是最新的答案。
    【解决方案4】:

    您不能直接调用 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>
    

    此帖Create a CRUD App using Blazor and ASP.NET Core 显示了从 Blazor 调用 JavaScript 的工作演示。

    【讨论】:

    猜你喜欢
    • 2021-04-01
    • 2020-06-06
    • 2020-09-06
    • 1970-01-01
    • 2021-06-06
    • 2020-10-22
    • 2020-10-27
    • 1970-01-01
    • 2020-10-17
    相关资源
    最近更新 更多