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

Blazor中按下Enter键实现RadzenTextBox焦点下移问题求助

解决Blazor Radzen组件按下Enter自动切换输入焦点问题

问题分析

你的方案未生效主要有几个原因:

  • JavaScript函数名称不匹配(C#中调用setFocus但JS定义的是onFocus)
  • DOM选择器不准确:循环生成的Radzen组件渲染后,nth-of-type无法精准定位下一个输入元素
  • 未正确阻止Enter键的默认行为(可能触发表单提交或组件自带的默认动作)
  • 未考虑RadzenDropDown渲染后是<select>元素,仅查找<input>会遗漏下拉框

解决方案

1. 替换JavaScript函数

将原有JS代码替换为以下逻辑,兼容<input>和<select>元素,自动查找当前焦点元素的下一个可聚焦元素:

window.focusNextInput = () => {
    const currentElement = document.activeElement;
    if (!currentElement) return;

    // 获取所有可聚焦的Radzen表单元素
    const focusableElements = Array.from(document.querySelectorAll(
        'input[rzinputtext], select[rzdropdown]'
    ));

    const currentIndex = focusableElements.indexOf(currentElement);
    // 找到下一个元素,若为最后一个则回到第一个(可根据需求调整)
    const nextElement = focusableElements[currentIndex + 1] || focusableElements[0];
    
    if (nextElement) {
        nextElement.focus();
    }
}

2. 修改Blazor组件代码

调整按键事件绑定

给所有需要切换焦点的Radzen控件添加统一的按键处理,同时阻止Enter键的默认行为:

@page "/"
@attribute [Authorize]
@using System.Text.Json;
@using Blazored.LocalStorage;
@inject IJSRuntime JSRuntime
@inject NavigationManager NavigationManager
@inject DialogService DialogService
@inject ContextMenuService ContextMenuService
@inject TooltipService TooltipService
@inject NotificationService NotificationService
@inject NavigationManager NavManager
@inject Blazored.LocalStorage.ILocalStorageService oLocalStore

<PageTitle>Form</PageTitle>
<div class="container">
    <div class="row">
        <div class="col-md-12">
            <h1 class="h3" style="display: block; text-align: center">Welcome Chris DeBrodie!</h1>
        </div>
    </div>
    <div class="row">
        <div class="col-md-12">
            <div class="form-group">
            </div>
        </div>
    </div>
    <div class="container">
        <div class="row">
            <div class="col-md-12">
                <div class="form-group">
                    @foreach (var (inputData, index) in inputCardData.Select((data, index) => (data, index)))
                    {
                        <div class="col-md-12">
                            @if (index == 0)
                            {
                                <!-- 第一个卡片的下拉框 -->
                                <RadzenDropDown TValue="string" 
                                               ValueProperty="BuildingName" 
                                               TextProperty="BuildingName" 
                                               Data="@buildingLists" 
                                               @bind-Value="inputData.BuildingName" 
                                               AllowSelectAll="false" 
                                               Placeholder="School Name" 
                                               Style="width: 100%; text-align: center"
                                               @onkeydown="HandleEnterKey" />
                            }

                            <RadzenCard Variant="Radzen.Variant.Filled">
                                <div class="form-group">
                                    <RadzenTextBox TextProperty="CPSNumber" 
                                                  Data="@surplusItemsNews" 
                                                  @bind-Value="inputData.CPSNumber" 
                                                  Placeholder="CPS Number" 
                                                  Style="width: 100%; text-align: left"
                                                  @onchange="@(value => OnAutoCompleteChange(value, index))" 
                                                  @oninput="() => AddNewCard(index)" 
                                                  AutoComplete="false"
                                                  @onkeydown="HandleEnterKey" />
                                </div>
                                <div class="form-group">
                                    <RadzenTextBox TextProperty="Description" 
                                                  Data="@surplusItemsNews" 
                                                  @bind-Value="inputData.Description" 
                                                  Placeholder="Item Description" 
                                                  Style="width: 100%"
                                                  @onchange="@(value => OnAutoCompleteChange(value, index))"
                                                  @onkeydown="HandleEnterKey" />
                                </div>
                                <div class="form-group">
                                </div>
                                <RadzenDropDown TValue="string" 
                                               ValueProperty="ReasonDescription" 
                                               TextProperty="ReasonDescription" 
                                               Data="@reasons" 
                                               @bind-Value="inputData.ReasonDescription" 
                                               Placeholder="Reason For Surplus" 
                                               Style="width: 100%"
                                               @onkeydown="HandleEnterKey" />
                            </RadzenCard>
                        </div>
                    }
                </div>
            </div>
        </div>
    </div>
</div>
<RadzenButton Style="width: 100%; min-width: 0px; min-height: 0px; height: 40px; display: block; background-color: #005570" Text="Review" Click="FinalizeList"></RadzenButton>

@code {
    [Inject]
    protected Surplus.WASPOService WASPOService { get; set; }
    protected System.Linq.IQueryable<Surplus.Models.WASPO.SurplusItemsNew> surplusItemsNews;
    protected System.Linq.IQueryable<Surplus.Models.WASPO.BuildingList> buildingLists;
    protected System.Linq.IQueryable<Surplus.Models.WASPO.Reason> reasons;

    public class FormData
    {
        public string BuildingName { get; set; }
        public string CPSNumber { get; set; }
        public string Description { get; set; }
        public string ReasonDescription { get; set; }
        public string SurplusSatus { get; set; }
    }

    [Inject]
    private ILocalStorageService localStorage { get; set; }
    private productDtoVM product = new();
    List<FormData> inputCardData;

    private async Task OnAutoCompleteChange(object value, int index)
    {
        // 保留原有的自动完成逻辑,若不需要可删除
    }

    // 统一处理Enter键事件
    private async Task HandleEnterKey(KeyboardEventArgs e)
    {
        if (e.Key == "Enter")
        {
            // 阻止默认行为(避免表单提交或组件默认动作)
            e.PreventDefault();
            // 调用JS函数切换焦点
            await JSRuntime.InvokeVoidAsync("focusNextInput");
        }
    }

    public Form()
    {
        inputCardData = new List<FormData>();
        inputCardData.Add(new FormData());
    }

    private int cardIdCounter = 1;
    [Inject]
    protected SecurityService Security { get; set; }

    private void AddNewCard(int index)
    {
        if (index == inputCardData.Count - 1)
        {
            inputCardData.Add(new FormData
            {
                CPSNumber = inputCardData[index].CPSNumber,
                Description = inputCardData[index].Description,
                ReasonDescription = inputCardData[index].ReasonDescription
            });
            cardIdCounter++;
        }
    }

    private async Task SaveInputCardDataToLocalStorage()
    {
        try
        {
            await localStorage.SetItemAsync("inputCardData", inputCardData);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error saving to local storage: {ex.Message}");
        }
    }

    private async Task LoadInputCardDataFromLocalStorage()
    {
        try
        {
            inputCardData = await localStorage.GetItemAsync<List<FormData>>("inputCardData");
            if (inputCardData == null)
            {
                inputCardData = new List<FormData>();
                inputCardData.Add(new FormData());
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error loading from local storage: {ex.Message}");
        }
    }

    protected override async Task OnInitializedAsync()
    {
        surplusItemsNews = await WASPOService.GetSurplusItemsNews();
        buildingLists = await WASPOService.GetBuildingLists();
        reasons = await WASPOService.GetReasons();
        await LoadInputCardDataFromLocalStorage();
    }

    private async Task FinalizeList()
    {
        await SaveInputCardDataToLocalStorage();
        NavManager.NavigateTo("/summary");
    }

    public productDtoVM inputData = new productDtoVM();
    [Inject]
    protected IJSRuntime JsRuntime { get; set; }

    public async Task HandleValidSubmit()
    {
    }
    public class productDtoVM
    {
        public string CPSNumber { get; set; }
        public string Description { get; set; }
        public string reason { get; set; }
    }
}

3. 关键修改说明

  • 统一按键处理函数HandleEnterKey,所有需要切换焦点的控件绑定该函数
  • 调用e.PreventDefault()阻止Enter键的默认行为,避免干扰焦点切换逻辑
  • JS函数通过document.activeElement获取当前焦点元素,基于Radzen组件的特征选择器精准定位所有可聚焦元素
  • 移除了原代码中冗余的按键处理逻辑,简化整体流程

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 18:42:33