主要方式:使用 scrollTo(0,1) -> scrollTo(0,0) 技巧强制 Safari 重新计算 viewport`
import` `{ useEffect } from 'react'`
/**
``* 修复 iOS 键盘收起后页面不恢复的问题
``*
``* 问题:iOS 在键盘收起后,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)
``}
``}, [])
`}``