Blazor FocusOnNavigate自动设置tabindex=-1的原因及解决方法
原因
FocusOnNavigate 自动添加 tabindex="-1" 是组件的预设设计逻辑,不是bug。
这个组件的核心设计目标是满足页面路由切换后的无障碍访问要求:导航完成后将焦点移动到指定选择器匹配的元素,让屏幕阅读器可以直接从页面内容区开始朗读,避免用户需要反复Tab遍历导航栏等重复元素。
按照这个设计的预期,这个初始焦点只是路由切换后的临时落点:如果匹配到的元素本身没有显式设置tabindex属性,组件会临时给它加上tabindex="-1"让元素可以被JS调用focus()方法聚焦——但在ASP.NET Core 6.0的原生实现中,聚焦完成后没有移除这个临时添加的属性,最终导致元素被排除在Tab键的正常遍历序列之外,焦点移走之后就没法再通过Tab切回来。
你提到的直接给input加autofocus不生效是正常现象:原生autofocus属性仅在页面初始静态加载时触发,Blazor的路由切换是局部DOM更新,不会重新触发页面加载流程,所以这个属性在路由导航场景下不会生效。
规避方案
你可以根据自己的场景选下面任意一种方案解决:
- 给需要初始聚焦的input元素显式设置
tabindex="0"FocusOnNavigate只会给没有显式声明tabindex属性的元素添加tabindex="-1",你手动给目标input加上tabindex="0"之后,组件不会覆盖你设置的属性值,聚焦完成后元素依然保留在正常的Tab遍历序列中,Tab移走后可以正常切回。这个方案改动最小,不需要额外写自定义逻辑。 - 自定义FocusOnNavigate逻辑,聚焦完成后清理临时属性
如果不想给元素手动加tabindex,可以自己实现一个轻量的导航聚焦逻辑,在JS聚焦动作完成后移除临时添加的tabindex="-1"属性,示例代码如下:
对应的JS方法可以放在@inject NavigationManager Navigation @inject IJSRuntime JS @* 放在App.razor中,替换原生的FocusOnNavigate组件 *@ @code { protected override void OnInitialized() { Navigation.LocationChanged += HandleLocationChanged; } private async void HandleLocationChanged(object? sender, LocationChangedEventArgs e) { // 等待新页面渲染完成 await Task.Yield(); await JS.InvokeVoidAsync("window.focusFirstInput"); } public void Dispose() { Navigation.LocationChanged -= HandleLocationChanged; } }index.html中:window.focusFirstInput = () => { const el = document.querySelector('input'); if (!el) return; const hadTabindex = el.hasAttribute('tabindex'); if (!hadTabindex) el.setAttribute('tabindex', '-1'); el.focus(); if (!hadTabindex) el.removeAttribute('tabindex'); }
内容的提问来源于stack exchange,提问作者Roeland
相关产品推荐
相关产品推荐

