MAUI安卓端切换.xaml页面后JavaScript .focus()函数失效问题
问题原因
- WebView焦点未恢复:从ScanningPage返回MainPage时,MAUI的WebView组件可能尚未重新获取安卓系统的原生焦点,此时调用DOM元素的
focus()无法触发键盘唤起。 - 渲染时机不匹配:硬编码的
Task.Delay(600)无法精准适配页面切换后的渲染流程,可能在弹窗DOM元素未完全渲染或WebView状态未稳定时执行focus操作。 - 异步方法设计缺陷:
ViewPopup使用async void类型,会导致状态更新与Blazor渲染周期不同步,无法保证弹窗渲染完成后再执行焦点逻辑。
解决办法
1. 修正页面导航逻辑,移除无效循环
修改MainPage.xaml.cs的BeginScan方法,无需循环等待页面返回,PushAsync完成后页面返回会自动继续执行后续代码:
public async Task<string> BeginScan() { await Navigation.PushAsync(new ScanningPage()); return ScanningPage.UserDesiresManualEntry ? string.Empty : "null"; }
2. 优化Blazor异步方法调用
修改Blazor代码中的TogglePage和ViewPopup,确保状态更新与渲染同步:
protected async Task TogglePage() { var navMain = Microsoft.Maui.Controls.Application.Current.MainPage as NavigationPage; var mainPageRoot = navMain.RootPage as MainPage; if (mainPageRoot == null) return; var returnValue = await mainPageRoot.BeginScan(); if (ScanningPage.UserDesiresManualEntry) { await ViewPopup(); ScanningPage.UserDesiresManualEntry = false; } } private async Task ViewPopup() { CanSeePopup = true; NeedsToRender = true; StateHasChanged(); // 立即触发组件渲染 await Task.Yield(); // 让UI线程优先完成渲染操作 }
3. 确保WebView获得原生焦点后再执行DOM聚焦
修改OnAfterRenderAsync方法,先让WebView获取安卓系统焦点,再调用JS聚焦逻辑:
protected override async Task OnAfterRenderAsync(bool firstRender) { if (NeedsToRender && CanSeePopup) { // 获取BlazorWebView实例,需在MainPage.xaml中给BlazorWebView设置x:Name="BlazorWebView" var webView = Microsoft.Maui.Controls.Application.Current.MainPage.FindByName<Microsoft.Maui.Controls.WebView>("BlazorWebView"); webView?.Focus(); // 让WebView获得原生焦点 await Task.Yield(); // 等待焦点状态稳定 var result = await JSR.InvokeAsync<string>("focusOnElement", "textInput"); TempInputValue = $"{NeedsToRender} {CanSeePopup} {result}"; NeedsToRender = false; StateHasChanged(); } }
4. 增强JS聚焦逻辑,确保元素就绪
更新Blazor中的JS函数,等待元素可见后再执行聚焦,并添加文本选中操作(安卓部分机型需要此步骤唤起键盘):
<script> async function focusOnElement(elementId) { var element = document.getElementById(elementId); if (!element) return `${elementId} not found`; // 等待元素在DOM中可见 while (element.offsetParent === null) { await new Promise(resolve => setTimeout(resolve, 50)); } element.focus(); element.setSelectionRange(0, element.value.length); // 选中文本,确保键盘唤起 return `${elementId} ${document.activeElement.id}`; } </script>
5. 补充BlazorWebView命名
在MainPage.xaml中给BlazorWebView组件添加x:Name属性,确保代码能找到实例:
<BlazorWebView x:Name="BlazorWebView" HostPage="wwwroot/index.html"> <BlazorWebView.Routes> <Route Route="/" ComponentType="{x:Type local:Main}" /> </BlazorWebView.Routes> </BlazorWebView>
内容的提问来源于stack exchange,提问作者Frasher Gray
相关产品推荐
相关产品推荐

