From 2816a6c0ddd0c4829039143d8db2402cdb0e763c Mon Sep 17 00:00:00 2001 From: hzm <934585316@qq.com> Date: Thu, 12 Mar 2026 22:31:34 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E7=A7=BB=E5=8A=A8=E7=AB=AF?= =?UTF-8?q?=E8=BF=9E=E7=BB=AD=E5=BC=B9=E6=A1=86=E5=BC=95=E8=B5=B7=E7=9A=84?= =?UTF-8?q?=E6=BB=9A=E5=8A=A8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/hooks/useBodyScrollLock.js | 60 +++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 9 deletions(-) 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