video-flow-b/hooks/useSafeArea.ts
2025-09-25 11:29:53 +08:00

65 lines
2.0 KiB
TypeScript

import { useState, useEffect } from 'react';
interface SafeAreaInsets {
top: number;
right: number;
bottom: number;
left: number;
}
export function useSafeArea() {
const [safeAreaInsets, setSafeAreaInsets] = useState<SafeAreaInsets>({
top: 0,
right: 0,
bottom: 0,
left: 0
});
const [viewportHeight, setViewportHeight] = useState(0);
useEffect(() => {
const updateSafeArea = () => {
// 获取 CSS 环境变量
const computedStyle = getComputedStyle(document.documentElement);
const top = parseInt(computedStyle.getPropertyValue('--sat').replace('px', '')) || 0;
const right = parseInt(computedStyle.getPropertyValue('--sar').replace('px', '')) || 0;
const bottom = parseInt(computedStyle.getPropertyValue('--sab').replace('px', '')) || 0;
const left = parseInt(computedStyle.getPropertyValue('--sal').replace('px', '')) || 0;
setSafeAreaInsets({ top, right, bottom, left });
// 设置动态视口高度
const vh = window.innerHeight;
setViewportHeight(vh);
document.documentElement.style.setProperty('--vh', `${vh * 0.01}px`);
};
updateSafeArea();
window.addEventListener('resize', updateSafeArea);
window.addEventListener('orientationchange', updateSafeArea);
// 延迟更新以处理移动端浏览器地址栏变化
const timeoutId = setTimeout(updateSafeArea, 500);
return () => {
window.removeEventListener('resize', updateSafeArea);
window.removeEventListener('orientationchange', updateSafeArea);
clearTimeout(timeoutId);
};
}, []);
return {
safeAreaInsets,
viewportHeight,
/** 获取考虑安全区域的样式 */
getSafeAreaStyle: (includeBottom = true) => ({
paddingTop: `max(1rem, ${safeAreaInsets.top}px)`,
paddingRight: `max(1rem, ${safeAreaInsets.right}px)`,
paddingBottom: includeBottom ? `max(1rem, ${safeAreaInsets.bottom}px)` : undefined,
paddingLeft: `max(1rem, ${safeAreaInsets.left}px)`,
})
};
}