diff --git a/app/hooks/useBodyScrollLock.js b/app/hooks/useBodyScrollLock.js index 4b76395..dca2a0b 100644 --- a/app/hooks/useBodyScrollLock.js +++ b/app/hooks/useBodyScrollLock.js @@ -1,18 +1,60 @@ -import { useEffect } from "react"; +import { useEffect, useRef } from "react"; -export function useBodyScrollLock(open) { - useEffect(() => { - if (!open) return; +// 全局状态:支持多个弹框“引用计数”式地共用一个滚动锁 +let scrollLockCount = 0; +let lockedScrollY = 0; +let originalBodyPosition = ""; +let originalBodyTop = ""; - const scrollY = window.scrollY; +function lockBodyScroll() { + scrollLockCount += 1; + + // 只有第一个锁才真正修改 body,避免多弹框互相干扰 + if (scrollLockCount === 1) { + lockedScrollY = window.scrollY || window.pageYOffset || 0; + originalBodyPosition = document.body.style.position || ""; + originalBodyTop = document.body.style.top || ""; document.body.style.position = "fixed"; - document.body.style.top = `-${scrollY}px`; + document.body.style.top = `-${lockedScrollY}px`; + document.body.style.width = "100%"; + } +} +function unlockBodyScroll() { + if (scrollLockCount === 0) return; + + scrollLockCount -= 1; + + // 只有全部弹框都关闭时才恢复滚动位置 + if (scrollLockCount === 0) { + document.body.style.position = originalBodyPosition; + document.body.style.top = originalBodyTop; + document.body.style.width = ""; + + // 恢复到锁定前的滚动位置,而不是跳到顶部 + window.scrollTo(0, lockedScrollY); + } +} + +export function useBodyScrollLock(open) { + const isLockedRef = useRef(false); + + useEffect(() => { + if (open && !isLockedRef.current) { + lockBodyScroll(); + isLockedRef.current = true; + } else if (!open && isLockedRef.current) { + unlockBodyScroll(); + isLockedRef.current = false; + } + + // 组件卸载或依赖变化时兜底释放锁 return () => { - document.body.style.position = ""; - document.body.style.top = ""; - window.scrollTo(0, scrollY); + if (isLockedRef.current) { + unlockBodyScroll(); + isLockedRef.current = false; + } }; }, [open]); } \ No newline at end of file