Blazor:点击内部按钮时如何避免onblur事件提前关闭面板?
解决Blazor滑入面板点击内部元素触发onblur关闭的问题
问题描述
我们实现了一个Blazor滑入面板组件,通过onblur事件实现点击面板外部时自动关闭,该功能正常运行。但遇到一个问题:点击面板内部的按钮或元素时,面板会先失去焦点触发onblur事件,导致面板提前关闭,无法正常执行内部元素的点击逻辑。
解决方案
核心思路是在面板的onblur事件中,判断失去焦点后新的焦点元素是否属于面板内部。如果是内部元素,则不执行关闭操作。具体实现如下:
1. 添加JS辅助方法
在项目全局脚本文件(如wwwroot/js/site.js)中添加以下方法,用于判断当前焦点元素是否属于面板内部:
window.isElementFocusedInside = function(element) { return element.contains(document.activeElement); };
2. 修改Blazor组件代码
Razor部分
<div class="slide-over-panel @(IsVisible ? "visible" : "")" tabindex="-1" @onblur="PanelBlurred" @ref="panelRef"> <div class="slide-over-content"> <!-- 面板内容 --> <CustomButton CallBackAction="OnActionButtonClick">Action Button</CustomButton> </div> </div>
C#逻辑部分
@inject IJSRuntime JSRuntime @code { private ElementReference panelRef; private bool IsVisible { get; set; } private bool wasVisible = false; protected override async Task OnAfterRenderAsync(bool firstRender) { if (IsVisible && !wasVisible) { await SetFocusOnPanel(); } wasVisible = IsVisible; } private async Task SetFocusOnPanel() { StateHasChanged(); await Task.Yield(); // 确保组件渲染完成后再聚焦 await panelRef.FocusAsync(); } private async Task PanelBlurred(FocusEventArgs e) { // 延迟100ms,让内部元素有足够时间获取焦点 await Task.Delay(100); // 判断当前焦点是否在面板内部 bool isFocusInside = await JSRuntime.InvokeAsync<bool>("isElementFocusedInside", panelRef); if (!isFocusInside) { ClosePanel(); } } private void OnActionButtonClick() { // 内部按钮的业务逻辑,现在不会被面板提前关闭打断 } private void ClosePanel() { IsVisible = false; StateHasChanged(); } }
3. 原CSS代码保持不变
.slide-over-panel { position: fixed; top: 0; right: -640px; width: 640px; height: 100%; transition: right 0.3s ease-in-out; z-index: 1000; overflow-x: hidden; } .slide-over-panel.visible { right: 0; } .slide-over-content { display: flex; flex-direction: column; height: 100%; width: 100%; max-width: 600px; background-color: white; box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3); padding: 24px; position: absolute; top: 0; right: 0; }
原理说明
- 通过
Task.Delay(100)等待内部元素完成焦点获取,避免因焦点切换时序问题导致误判。 - 利用JS的
element.contains()方法检查当前激活元素是否属于面板的子元素,精准区分内部/外部点击。 - 优化
SetFocusOnPanel方法,去掉不必要的固定延迟,改用Task.Yield()确保组件渲染完成后再执行聚焦操作。
内容的提问来源于stack exchange,提问作者coding1223322
相关产品推荐
相关产品推荐

