本文介绍在 next.js 应用中,当聊天模态框内的输入框获得焦点时,通过 react 状态驱动方式自动将模态框高度缩至 55%,避免软键盘遮挡输入区域的完整实现方案。
本文介绍在 next.js 应用中,当聊天模态框内的输入框获得焦点时,通过 react 状态驱动方式自动将模态框高度缩至 55%,避免软键盘遮挡输入区域的完整实现方案。
在移动端 Web 应用(尤其是 ios safari 和部分 android 浏览器)中,软键盘弹出时往往不会自动触发 resize 事件,也不会改变 window.innerHeight 的值,导致固定定位或绝对定位的模态框被键盘遮盖——这是 Next.js(及多数 React SSR 应用)中聊天组件常见的交互痛点。
核心思路是:不依赖 dom 操作,而采用声明式状态控制样式。直接将模态框高度绑定到 React state,并在 的 onFocus 与 onBlur 生命周期中切换高度值,既符合 React 最佳实践,又规避了服务端渲染(SSR)环境下 document 未定义导致的报错风险。
✅ 推荐实现方式(状态驱动 + 响应式样式)
'use client'; // Next.js 13+ 必须标记为客户端组件 import { useState, useEffect } from 'react'; export default function ChatModal() { const [modalHeight, setModalHeight] = useState<string>('100%'); // 可选:监听窗口尺寸变化(增强兼容性,如横竖屏切换) useEffect(() => { const handleResize = () => { // 避免在键盘收起后残留窄高度(部分浏览器 onBlur 不可靠) if (window.visualViewport?.height > 0.7 * window.screen.height) { setModalHeight('100%'); } }; window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []); const handleinputFocus = () => setModalHeight('55%'); const handleInputBlur = () => setModalHeight('100%'); return ( <div className="fixed inset-0 bg-black/20 flex items-end z-50"> {/* 模态框容器 —— 高度由 state 控制 */} <div className="w-full bg-white rounded-t-2xl shadow-lg overflow-hidden transition-all duration-300" style={{ height: modalHeight }} > {/* 聊天内容区(可滚动) */} <div className="h-[calc(100%-80px)] p-4 overflow-y-auto"> <div className="space-y-3"> <div className="bg-blue-100 text-blue-800 px-4 py-2 rounded-lg max-w-[80%] ml-auto"> Hello! How can I help? </div> </div> </div> {/* 输入区 —— 固定底部,确保始终可见 */} <div className="p-3 border-t border-gray-200"> <input type="text" placeholder="Type a message..." className="w-full px-4 py-3 bg-gray-100 rounded-full focus:outline-none focus:ring-2 focus:ring-blue-500" onFocus={handleInputFocus} onBlur={handleInputBlur} /> </div> </div> </div> ); }
⚠️ 关键注意事项
- 必须添加 ‘use client’:Next.js 13+ App router 中,DOM 操作和事件监听只能在客户端组件中执行,服务端组件中 window 或 document 未定义。
- 避免直接操作 DOM:原问题中通过 getElementsByClassName 获取元素并修改 style.height,不仅冗余,且在组件重渲染时易失效;React 状态驱动更稳定、可预测。
- onBlur 并非 100% 可靠:某些 Android 浏览器在键盘收起时可能不触发 blur。因此建议配合 window.visualViewport.height 监听 resize 事件作为兜底(如上例所示),判断当前视口是否恢复“正常比例”后自动还原高度。
- CSS 过渡增强体验:添加 transition-all duration-300 可使高度变化平滑,避免突兀跳变。
- 移动端适配补充:若需更高兼容性,可在 上添加 scrollIntoView({ behavior: ‘smooth’, block: ‘nearest’ }),确保聚焦时输入框始终处于可视区域。
✅ 总结
解决键盘遮挡模态框输入框的问题,本质是将 ui 响应从命令式 DOM 操作升级为声明式状态管理。通过 useState 控制高度、合理使用 onFocus/onBlur,辅以 visualViewport 监听兜底,即可在 Next.js 中实现轻量、健壮、跨平台友好的键盘自适应模态框。该方案无需第三方库,零运行时开销,适合生产环境长期维护。