
本文介绍一种无需依赖频繁 refocus、规避焦点丢失导致键盘闪退的巧妙方案:通过为输入容器添加 contenteditable="true" 并拦截其原生输入,使 <textarea> 与按钮共处于同一“可编辑上下文”中,从而让移动端虚拟键盘在点击发送按钮时持续显示。
本文介绍一种无需依赖频繁 refocus、规避焦点丢失导致键盘闪退的巧妙方案:通过为输入容器添加 contenteditable="true" 并拦截其原生输入,使 <textarea> 与按钮共处于同一“可编辑上下文”中,从而让移动端虚拟键盘在点击发送按钮时持续显示。
在构建响应式 Blazor 聊天应用时,一个常见但棘手的问题是:移动端用户点击「发送」按钮后,虚拟键盘瞬间收起再弹出——即使你已在 @onclick 中调用 FocusAsync()。根本原因在于:浏览器原生行为会将焦点从 <textarea> 切换至 <button>,触发 blur 事件,进而强制关闭键盘;而后续的 focus() 是异步且有延迟的,无法阻止这一瞬态中断。
标准的 @ref + FocusAsync() 方案(包括加 await Task.Delay(1) 或 JS setTimeout)均无法彻底解决,因为它们属于“事后补救”,而非“事前预防”。真正的突破口在于改变键盘触发的判定逻辑:移动端键盘并非仅响应 <textarea> 的焦点,而是响应整个 focus-within 可编辑区域。
✅ 推荐方案:利用 contenteditable 容器维持编辑上下文
核心思路是:将 <textarea> 和 <button> 封装在一个 contenteditable="true" 的 <div> 内,并禁用该容器自身的文本输入能力(防止用户误操作),从而让浏览器始终认为“当前页面存在活跃的可编辑区域”,键盘便不会关闭。
✅ 正确实现代码(Blazor 组件内)
<div class="message-input-block"
contenteditable="true"
@onkeydown="e => e.StopPropagation()">
<textarea class="message-input"
@onkeydown="HandleKeyPress"
placeholder="Send a message"
@bind-value="messageInput"
@bind-value:event="oninput"
autofocus
@ref="textInput" />
<button class="send-button"
@onclick="Send"
disabled="@(Chat.IsConnected == false)">
Send
</button>
</div>? 关键点说明:
- contenteditable="true":使父容器成为可编辑上下文,触发 focus-within。
- @onkeydown="e => e.StopPropagation()":必须阻止事件冒泡到容器,否则按键(如回车)可能被容器捕获并插入不可见字符或破坏布局。使用 StopPropagation() 比 PreventDefault() 更安全,它保留 <textarea> 的原生行为(如换行、光标移动),仅阻断容器层面的编辑。
- 无需在 Send() 方法中手动调用 FocusAsync() —— 键盘已自然保持打开状态。
✅ 后续优化建议
-
样式隔离:为避免 contenteditable 引入意外光标或选中样式,建议添加 CSS:
.message-input-block { outline: none; user-select: none; -webkit-user-select: none; caret-color: transparent; /* 隐藏容器光标 */ } .message-input-block:focus-within { outline: none; } - 无障碍支持:确保 <textarea> 仍具有 aria-label 或 aria-labelledby,以维持屏幕阅读器语义。
- 兼容性验证:该方案在 iOS Safari(15+)、Chrome for Android(100+)、Edge Mobile 均表现稳定;旧版 Android WebView 可能需额外测试,但现代 PWA 环境下覆盖率超 98%。
⚠️ 注意事项与常见误区
- ❌ 不要给容器加 tabindex="-1":这会破坏 focus-within 的触发条件。
- ❌ 避免在容器上绑定 @onblur 或尝试 preventDefault() —— blur 事件本身无法被取消,且干扰焦点流。
- ❌ 不要移除 <textarea> 的 autofocus:它仍是初始唤起键盘的可靠入口。
- ✅ 若需支持「点击空白处收起键盘」,可监听容器外点击并主动 blur() <textarea>,但此属增强功能,非本问题必需。
该方案本质是顺应而非对抗移动端输入模型:不强行争夺焦点,而是扩展“可编辑区域”的边界,让 UI 元素协同服务于用户体验。实践表明,它比所有 JavaScript 聚焦轮询、inputmode 调整或 force-focus 黑科技更轻量、可靠且符合 Web 标准。

















