Blazor同级事件冲突解决:点击列表项时onfocusout优先于onclick触发怎么办
解决方案
方案1:将列表项的onclick替换为onmousedown(最推荐)
click事件触发时机晚于focusout是浏览器默认行为:focusout会在鼠标按下其他元素时立刻触发,而click需要等鼠标按下+松开的完整动作完成才会触发。mousedown的触发时机早于focusout,可以直接解决优先级问题:
- 给列表项绑定
onmousedown事件替代原有的onclick - 在
mousedown事件回调中调用event.preventDefault(),可以阻止输入框失去焦点,从根源上避免focusout触发
示例代码(Blazor版本):
<input type="search" @onfocusout="HandleFocusOut" /> <ul class="dropdown"> <li @onmousedown="(e) => HandleItemClick(e, item)">@item.Text</li> </ul> @code { void HandleItemClick(MouseEventArgs e, SelectItem item) { e.PreventDefault(); // 阻止输入框失焦 // 原有点击逻辑,比如赋值给输入框、关闭下拉 } void HandleFocusOut() { // 失焦关闭下拉逻辑 } }
方案2:给focusout逻辑添加短延迟
如果不想修改原有事件绑定,可以给focusout的执行逻辑加150~200ms的延迟,预留足够时间让click事件先执行完成:
示例代码:
@inject IJSRuntime JSRuntime <input type="search" @onfocusout="HandleFocusOut" /> <ul class="dropdown"> <li @onclick="HandleItemClick">List Item One</li> </ul> @code { private CancellationTokenSource? _focusOutCts; async Task HandleFocusOut() { _focusOutCts = new CancellationTokenSource(); try { await Task.Delay(200, _focusOutCts.Token); // 原有失焦逻辑,关闭下拉 } catch (OperationCanceledException) { // 点击了列表项,取消失焦逻辑 } } void HandleItemClick() { // 先取消失焦逻辑的执行 _focusOutCts?.Cancel(); // 原有点击逻辑 } }
方案3:判断失焦的目标元素是否属于下拉区域
利用focusout事件的RelatedTarget属性,判断新获得焦点的元素是否在下拉列表内部,如果是则不执行失焦关闭逻辑:
<input type="search" @onfocusout="HandleFocusOut" /> <ul class="dropdown" @ref="_dropdownRef"> <li @onclick="HandleItemClick">List Item One</li> </ul> @code { private ElementReference _dropdownRef; [Inject] private IJSRuntime JSRuntime { get; set; } async Task HandleFocusOut(FocusEventArgs e) { // 调用JS判断新的焦点元素是否在下拉列表内 var isClickInsideDropdown = await JSRuntime.InvokeAsync<bool>("isElementInside", e.RelatedTarget, _dropdownRef); if (!isClickInsideDropdown) { // 只有失焦到下拉外部才执行关闭逻辑 } } void HandleItemClick() { // 原有点击逻辑 } }
对应的JS辅助方法:
function isElementInside(target, container) { if (!target) return false; return container.contains(target); }
内容的提问来源于stack exchange,提问作者Reptar
相关产品推荐
相关产品推荐

