Blazor 如何将焦点设置为InputText元素?

Blazor 如何将焦点设置为InputText元素?,blazor,blazor-server-side,Blazor,Blazor Server Side,使用,我试图以编程方式将焦点设置为输入元素 不幸的是,这个示例使用了一个标准的,而我想将它用于一个 Microsoft示例使用的扩展方法采用ElementReference: 公共静态任务焦点(此ElementReference elementRef,IJSRuntime jsRuntime) { 返回jsRuntime.InvokeAsync( “exampleJsFunctions.focusElement”, elementRef); } 使用InputText,我看不出有办法获得这样的

使用,我试图以编程方式将焦点设置为输入元素

不幸的是,这个示例使用了一个标准的
,而我想将它用于一个

Microsoft示例使用的扩展方法采用
ElementReference

公共静态任务焦点(此ElementReference elementRef,IJSRuntime jsRuntime)
{
返回jsRuntime.InvokeAsync(
“exampleJsFunctions.focusElement”,
elementRef);
}
使用
InputText
,我看不出有办法获得这样的
ElementReference

为我自己的
Focus()
重载提供一个
InputText
,但编译后没有显示可视化结果。所以我是无知的

我的问题
如何通过编程将焦点设置为
InputText
元素?

您可以向
InputText
添加
id
参数,并修改
focus
方法和JavaScript代码

public异步任务焦点(string elementId)
{
等待JSRuntime.InvokeVoidAsync(“exampleJsFunctions.focusElement”,elementId);
}
focusElement:函数(id){
常量元素=document.getElementById(id);
元素focus();
}

注意:这与其说是一个合适的解决方案,不如说是一个变通方法,但Blazor似乎并不直接支持它。

有几种方法可以通过Blazor本机方式将焦点设置在元素上。这里有一个:

创建一个从
InputBase
派生的类,该类是
InputText
的基类,具有与InputText相同的功能。简而言之,复制到新创建的类,并添加必要的功能。这是一个新类:TextBox.cs

public class TextBox : InputBase<string>
    {

        private ElementReference InputRef;
        protected override void BuildRenderTree(RenderTreeBuilder builder)
    {

            builder.OpenElement(0, "input");
    builder.AddMultipleAttributes(1, AdditionalAttributes);
    builder.AddAttribute(2, "class", CssClass);
    builder.AddAttribute(3, "value", BindConverter.FormatValue(CurrentValue));
    builder.AddAttribute(4, "onchange", EventCallback.Factory.CreateBinder<string>
        (this, __value => CurrentValueAsString = __value, CurrentValueAsString));
    builder.AddElementReferenceCapture(5, (value) => {
                InputRef = value; } );


            builder.CloseElement();


    }
        [Inject] IJSRuntime JSRuntime { get; set; }

        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if (firstRender)
            {
                await JSRuntime.InvokeVoidAsync("exampleJsFunctions.focusElement", InputRef);
            }
        }

        protected override bool TryParseValueFromString(string value, out string result, out string validationErrorMessage)
        {
        result = value;
        validationErrorMessage = null;
        return true;
        }
        }

   } 
公共类文本框:InputBase
{
私有元素引用InputRef;
受保护的覆盖void BuildRenderTree(RenderTreeBuilder)
{
builder.OpenElement(0,“输入”);
builder.AddMultipleAttributes(1,附加属性);
builder.AddAttribute(2,“类”,CssClass);
builder.AddAttribute(3,“值”,BindConverter.FormatValue(CurrentValue));
AddAttribute(4,“onchange”,EventCallback.Factory.CreateBinder
(这,_值=>CurrentValueAsString=_值,CurrentValueAsString));
builder.AddElementReferenceCapture(5,(值)=>{
InputRef=value;});
builder.CloseElement();
}
[Inject]IJSRuntime JSRuntime{get;set;}
AfterRenderAsync(bool firstRender)上受保护的重写异步任务
{
if(firstRender)
{
等待JSRuntime.InvokeVoidAsync(“exampleJsFunctions.focusElement”,InputRef);
}
}
受保护的重写bool TryParseValueFromString(字符串值、输出字符串结果、输出字符串验证错误消息)
{
结果=值;
validationErrorMessage=null;
返回true;
}
}
} 
将此脚本放在_Host.cshtml文件的底部,就在下面


window.exampleJsFunctions=
{
焦点元素:函数(元素){
元素focus();
}
};
注意事项: 1.定义ElementReference变量以保存对输入元素的引用。 2.在BuildRenderTree方法中,我添加了捕获对 输入元素 3.从OnAfterRenderAsync方法调用focusElement JavaScript函数。 这只执行一次。请注意,我无法使用OnInitializedAsync 方法,但ElementReference变量可能 包含空值。 4.请注意,如果没有EditForm,则无法运行任何窗体组件

重要信息:当浏览器处于最小化状态时,按Ctrl+F5可能会干扰在文本元素中查看光标

使用代码:

提交
@代码{
私人雇员=新雇员();
私人无效手册提交()
{
Console.WriteLine(“OnValidSubmit”);
}
公营雇员
{
公共int ID{get;set;}=1;
公共字符串名称{get;set;}=“Nancy”;
}
} 

我可以通过直接在Host.chtml文件中输入JavaScript来实现这一点(您也可以像演练建议的那样添加一个.js文件):

然后在razor页面(或组件)中,注入
IJSRuntime
,添加
ElementReference
,并将其绑定到要关注的元素(注意:方法名称已更改为符合命名标准):

@inject IJSRuntime
@使用JSInteropClass
将焦点设置为用户名
@代码{
私有元素引用用户名;
公共异步任务SetFocusAsync()
{
等待username.FocusAsync(JSRuntime);
}
}

.NET5中,它将更加简单:

<button @onclick="() => textInput.FocusAsync()">Set focus</button>
<input @ref="textInput"/>
设置焦点
注意:此功能是在中引入的,因此在最终版本之前可能会更改

还值得一提的是,in是通过JS模块导出/导入引入的。所以,如果您仍然需要使用JSInterop,请不要污染
窗口
对象

更新:.NET 5已发布,此功能的工作方式不变


还发现了一个很酷的方法,它可以为您提供一些方便的JS技巧,例如:聚焦以前的活动元素,而不必使用
@ref
。请参阅文档。

现在.net 5可能已经过时了,但如果您不想硬编码元素的Id或派生自己的输入类,实现这一点的简单方法是只向元素添加CSS类,然后使用getElementsByClassName查找并设置该类的焦点

创建包含辅助对象的脚本:

var JSHelpers = JSHelpers || {};

JSHelpers.setFocusByCSSClass = function () {
    var elems = document.getElementsByClassName("autofocus");
    if (elems.length == 0)
        return;
    elems[0].focus();
};
创建一个共享的“AutofocusByCSS”组件,以便在正确的时间处理调用JS:

@inject IJSRuntime JSRuntime
@code {
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender) JSRuntime.InvokeVoidAsync("JSHelpers.setFocusByCSSClass");
    }
}   
然后在您的页面中:

<InputText @bind-Value="editmodel.someThing" class="form-control autofocus" />

<AutofocusByCSS />

在任何事情上工作
@inject IJSRuntime JSRuntime
@using JsInteropClasses

<input @ref="username" />
<button @onclick="SetFocusAsync">Set focus on username</button>

@code {
    private ElementReference username;

    public async Task SetFocusAsync()
    {
        await username.FocusAsync(JSRuntime);
    }
}
<button @onclick="() => textInput.FocusAsync()">Set focus</button>
<input @ref="textInput"/>
var JSHelpers = JSHelpers || {};

JSHelpers.setFocusByCSSClass = function () {
    var elems = document.getElementsByClassName("autofocus");
    if (elems.length == 0)
        return;
    elems[0].focus();
};
@inject IJSRuntime JSRuntime
@code {
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender) JSRuntime.InvokeVoidAsync("JSHelpers.setFocusByCSSClass");
    }
}   
<InputText @bind-Value="editmodel.someThing" class="form-control autofocus" />

<AutofocusByCSS />