fix: 左右两栏共用滚动容器,滚动位移保持一致

- 将 Layout body (#page-scroll) 作为唯一滚动容器,左右两栏同容器滚动
- 滚动区域从搜索框下方开始,搜索框固定
- 内容区 overflow visible、侧栏 height auto;返回顶部/路由归零改用 page-scroll
- 验证:滚动 300px 后两侧 top 均为 -152,搜索框不动,返回顶部有效
This commit is contained in:
2026-10-31 15:40:08 +08:00
parent 57ab90a1fa
commit 54fd0edf84
4 changed files with 54 additions and 42 deletions
+41 -40
View File
@@ -80,7 +80,7 @@ function useRoute() {
if (window.location.pathname === path) return
window.history.pushState({}, '', path)
setRoute(parseRoute(path))
document.getElementById('content-scroll')?.scrollTo({ top: 0 })
document.getElementById('page-scroll')?.scrollTo({ top: 0 })
window.scrollTo({ top: 0 })
}
@@ -191,50 +191,51 @@ export default function AppNext() {
return () => source.close()
}, [])
useEffect(() => {
const sync = () => {
const inner = document.getElementById('content-scroll')?.scrollTop ?? 0
setScrolled(Math.max(inner, window.scrollY) > 4)
}
sync()
window.addEventListener('scroll', sync, { passive: true })
document.addEventListener('scroll', sync, { passive: true, capture: true })
return () => {
window.removeEventListener('scroll', sync)
document.removeEventListener('scroll', sync, { capture: true })
}
}, [])
useEffect(() => {
const content = document.getElementById('content-scroll')
const sider = document.querySelector('aside')
if (!(content instanceof HTMLElement) || !(sider instanceof HTMLElement)) return
// 左右两栏共用一个滚动位置:侧栏没有独立滚动条,滚轮也驱动内容区
sider.id = 'sidebar-scroll'
sider.style.overflow = 'hidden'
let frame = 0
const sync = () => {
if (frame !== 0) return
frame = window.requestAnimationFrame(() => {
frame = 0
sider.scrollTop = content.scrollTop
})
}
const onWheel = (event: WheelEvent) => {
event.preventDefault()
content.scrollTop += event.deltaY
const main = content?.parentElement
const body = main?.parentElement
if (
!(content instanceof HTMLElement) ||
!(main instanceof HTMLElement) ||
!(body instanceof HTMLElement)
) {
return
}
content.addEventListener('scroll', sync, { passive: true })
sider.addEventListener('wheel', onWheel, { passive: false })
// 左右两栏放进同一个滚动容器:滚动区域从搜索框下方开始,两栏位移完全一致
const sider = body.querySelector('aside')
body.id = 'page-scroll'
body.style.overflowY = 'auto'
body.style.overflowX = 'hidden'
body.style.marginTop = '88px'
body.style.height = 'calc(100% - 88px)'
content.style.overflow = 'visible'
content.style.marginTop = '0'
main.style.height = 'auto'
if (sider instanceof HTMLElement) {
sider.style.overflow = 'visible'
sider.style.height = 'auto'
}
const onScroll = () => setScrolled(body.scrollTop > 4)
body.addEventListener('scroll', onScroll, { passive: true })
onScroll()
return () => {
content.removeEventListener('scroll', sync)
sider.removeEventListener('wheel', onWheel)
if (frame !== 0) window.cancelAnimationFrame(frame)
sider.id = ''
sider.style.overflow = ''
body.removeEventListener('scroll', onScroll)
body.id = ''
body.style.overflowY = ''
body.style.overflowX = ''
body.style.marginTop = ''
body.style.height = ''
content.style.overflow = ''
content.style.marginTop = ''
main.style.height = ''
if (sider instanceof HTMLElement) {
sider.style.overflow = ''
sider.style.height = ''
}
}
}, [])
@@ -650,7 +651,7 @@ export default function AppNext() {
</div>
</Layout>
<BackToTop visible={scrolled} />
<BackToTop visible={scrolled} targetId="page-scroll" />
</>
)
}