import { useEffect } from 'react'
/**
* 修复 iOS 键盘收起后页面不恢复的问题
*
* 问题:iOS Safari 在键盘收起后,visualViewport.pageTop 不会自动归零,
* 导致页面视觉上仍然被推上去
*
* 解决方案:
* 1. 监听 visualViewport.resize 事件
* 2. 检测键盘弹起/收起(viewport 高度变化超过 100px)
* 3. 键盘弹起时:滚动到顶部消除空白
* 4. 键盘收起时:使用 scrollTo(0,1) -> scrollTo(0,0) 技巧强制 Safari 重新计算 viewport
*/
export const useIOSKeyboardFix = () => {
useEffect(() => {
if (typeof window === 'undefined' || !window.visualViewport) return
let previousHeight = window.visualViewport.height
const handleViewportResize = () => {
const currentHeight = window.visualViewport!.height
const heightDiff = currentHeight - previousHeight
// 键盘弹起:高度减少超过 100px,滚动到顶部消除空白
if (heightDiff < -100) {
setTimeout(() => {
window.scrollTo(0, 0)
document.documentElement.scrollTop = 0
document.body.scrollTop = 0
}, 500)
}
// 键盘收起:高度增加超过 100px,重置 viewport 位置
else if (heightDiff > 100) {
requestAnimationFrame(() => {
const viewportOffsetTop = window.visualViewport?.pageTop || 0
if (viewportOffsetTop !== 0) {
// 使用经典的 iOS scrollTo(0,1) -> scrollTo(0,0) 技巧强制 Safari 重新计算 viewport
window.scrollTo(0, 1)
requestAnimationFrame(() => {
window.scrollTo(0, 0)
document.documentElement.scrollTop = 0
document.body.scrollTop = 0
})
} else {
// viewport 正常,直接重置
window.scrollTo(0, 0)
document.documentElement.scrollTop = 0
document.body.scrollTop = 0
}
})
}
previousHeight = currentHeight
}
window.visualViewport.addEventListener('resize', handleViewportResize)
return () => {
window.visualViewport?.removeEventListener('resize', handleViewportResize)
}
}, [])
}