Blazor Server应用:点击非按钮区域后恢复最后点击按钮焦点的方案
解决方案
问题原因
你之前用原生onblur="this.focus()"无效,是因为Blazor Server的DOM操作受服务器端渲染生命周期限制,原生JS事件的执行时机和Blazor的状态更新不同步;而且当点击页面其他区域时,焦点会先转移到其他元素,直接在blur事件里调用focus()会被后续操作覆盖。
可行方案:结合ElementReference与JS互操作
步骤1:在Razor组件中定义按钮引用和状态变量
<button class="icon-button" @onclick="SubPage1" @ref="targetButton">打开子页面</button>
@code { // 绑定按钮的DOM引用 private ElementReference targetButton; // 标记按钮是否需要保持焦点(点击后激活) private bool keepButtonFocused = false; private async Task SubPage1() { // 这里写你的打开子页面逻辑 keepButtonFocused = true; // 点击后先主动聚焦按钮 await JSRuntime.InvokeVoidAsync("focusElement", targetButton); } protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { // 注册页面全局点击监听,判断是否点击在按钮外 await JSRuntime.InvokeVoidAsync("registerOutsideClickListener", DotNetObjectReference.Create(this)); } } // 供JS调用的方法,检查是否需要重新聚焦按钮 [JSInvokable] public async Task ReFocusButtonIfNeeded() { if (keepButtonFocused) { await JSRuntime.InvokeVoidAsync("focusElement", targetButton); } } }
步骤2:添加JS辅助函数
将以下代码放在_Host.cshtml的<script>标签中,或者组件内部的<script>标签里:
// 聚焦指定元素 function focusElement(element) { element.focus(); } // 注册页面点击监听,判断点击区域是否在按钮外 function registerOutsideClickListener(dotNetRef) { document.addEventListener('click', (event) => { const button = document.querySelector('.icon-button'); // 如果点击的不是按钮本身或其子元素 if (button && !button.contains(event.target)) { // 调用Blazor组件的方法检查是否需要重新聚焦 dotNetRef.invokeMethodAsync('ReFocusButtonIfNeeded'); } }); }
简化版方案(仅处理blur事件)
如果不需要全局监听,也可以改进blur事件的处理,通过延迟执行确保焦点能重新设置:
<button class="icon-button" @onclick="SubPage1" @onblur="HandleButtonBlur" @ref="targetButton">打开子页面</button>
@code { private ElementReference targetButton; private bool shouldRetainFocus = false; private async Task SubPage1() { // 打开子页面逻辑 shouldRetainFocus = true; } private async Task HandleButtonBlur() { if (shouldRetainFocus) { // 延迟10毫秒,等待其他元素的焦点操作完成 await Task.Delay(10); await JSRuntime.InvokeVoidAsync("focusElement", targetButton); } } }
同样需要上面的focusElement JS函数。
内容的提问来源于stack exchange,提问作者Mdarende
相关产品推荐
相关产品推荐

