You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor:EditForm.Model变更后如何保留原输入框的焦点状态

通用解决方案:自定义保留焦点的EditForm组件

该方案无需修改现有表单内的输入组件代码,仅需替换原有EditForm标签即可实现焦点自动保留,适配所有Blazor原生输入组件及自定义输入组件。

步骤1:添加全局JS辅助函数

将以下代码添加到项目的入口HTML文件中(Blazor WebAssembly项目为wwwroot/index.html,Blazor Server项目为Pages/_Layout.cshtml/Pages/_Host.cshtml):

window.FocusPreserver = {
    // 保存表单内当前聚焦元素的唯一选择器
    saveActiveElement: function (formElement) {
        const activeEl = document.activeElement;
        // 仅当活跃元素属于当前表单时才记录
        if (!activeEl || !formElement.contains(activeEl)) return null;
        
        if (activeEl.id) return `#${activeEl.id}`;
        if (activeEl.name) return `${activeEl.tagName}[name="${activeEl.name}"]`;
        // 无id/name时用标签名+同级索引匹配
        const sameTagSiblings = Array.from(formElement.querySelectorAll(activeEl.tagName));
        const elIndex = sameTagSiblings.indexOf(activeEl);
        return `${activeEl.tagName}:nth-of-type(${elIndex + 1})`;
    },
    // 根据保存的选择器恢复焦点
    restoreFocus: function (formElement, selector) {
        if (!selector) return;
        const targetEl = formElement.querySelector(selector);
        targetEl?.focus();
    }
};

步骤2:实现自定义EditForm组件

在项目中新建FocusPreservingEditForm.cs类,继承原生EditForm:

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.JSInterop;

public class FocusPreservingEditForm : EditForm
{
    [Inject] private IJSRuntime JSRuntime { get; set; }
    private ElementReference _formDomRef;
    private string _savedActiveElSelector;

    protected override async Task OnParametersSetAsync()
    {
        // 检测到Model变更、即将触发重渲染前,先保存当前焦点
        if (Model != null && PreviousModel != null && !Model.Equals(PreviousModel))
        {
            _savedActiveElSelector = await JSRuntime.InvokeAsync<string>(
                "FocusPreserver.saveActiveElement", 
                _formDomRef
            );
        }
        await base.OnParametersSetAsync();
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);
        // 重渲染完成后恢复焦点
        if (!string.IsNullOrEmpty(_savedActiveElSelector))
        {
            await JSRuntime.InvokeVoidAsync(
                "FocusPreserver.restoreFocus", 
                _formDomRef, 
                _savedActiveElSelector
            );
            _savedActiveElSelector = null;
        }
    }

    protected override void BuildRenderTree(RenderTreeBuilder builder)
    {
        builder.OpenElement(0, "form");
        builder.AddMultipleAttributes(1, AdditionalAttributes);
        // 捕获表单的DOM引用
        builder.AddElementReferenceCapture(2, domRef => _formDomRef = domRef);
        builder.AddContent(3, ChildContent);
        builder.CloseElement();
    }
}

步骤3:替换原有EditForm

直接将项目中所有表单的<EditForm>标签替换为<FocusPreservingEditForm>即可,其余代码无需修改:

<FocusPreservingEditForm Model="model">
    <!-- 原有输入组件完全不用修改 -->
    <InputText @bind-Value="model.Name" /> 
    ...数十个其他输入组件
</FocusPreservingEditForm>

适配说明

  • 若表单内输入组件为动态生成、重渲染后顺序会发生变化,只需给每个输入组件加唯一的id或name属性,即可保证选择器精准匹配
  • 若你的Model为引用类型且重写了Equals方法,可自行调整OnParametersSetAsync中的Model变更判断逻辑,适配业务需求
  • 该组件完全兼容原生EditForm的所有参数、验证逻辑及用法

内容的提问来源于stack exchange,提问作者Liero

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 13:24:03