diff --git a/src/client/theme-default/composables/outline.ts b/src/client/theme-default/composables/outline.ts index d9eda9c123be..5cc916ca4581 100644 --- a/src/client/theme-default/composables/outline.ts +++ b/src/client/theme-default/composables/outline.ts @@ -8,6 +8,8 @@ const ignoreRE = /\b(?:VPBadge|header-anchor|footnote-ref|ignore-header)\b/ // cached list of anchor elements from resolveHeaders const resolvedHeaders: { element: HTMLHeadElement; link: string }[] = [] +let asideOutlineLinkDomList: NodeListOf | null = null +let asideContainerDom: HTMLDivElement | null = null export function resolveTitle(theme: DefaultTheme.Config): string { return ( @@ -99,6 +101,27 @@ export function useActiveAnchor( window.removeEventListener('scroll', onScroll) }) + function scrollToActiveLink(i: number) { + if (!asideContainerDom) { + asideContainerDom = document.querySelector('.aside-container')! + } + const containerClientHeight = container.value.clientHeight + const asideContainerClientHeight = asideContainerDom.clientHeight + if (containerClientHeight > asideContainerClientHeight) { + if (!asideOutlineLinkDomList) { + asideOutlineLinkDomList = document.querySelectorAll( + '.VPDocOutlineItem.root .outline-link' + ) + } + const height = asideOutlineLinkDomList[i]?.clientHeight + if (height) { + asideContainerDom.scrollTo({ + top: i * height + }) + } + } + } + function setActiveLink() { if (!isAsideEnabled.value) { return @@ -137,14 +160,18 @@ export function useActiveAnchor( } // find the last header above the top of viewport - let activeLink: string | null = null - for (const { link, top } of headers) { + let activeIndex: number | null = null + for (let i = 0; i < headers.length; i++) { + const { top } = headers[i] if (top > scrollY + getScrollOffset() + 4) { break } - activeLink = link + activeIndex = i + } + if (activeIndex !== null) { + scrollToActiveLink(activeIndex) + activateLink(headers[activeIndex].link) } - activateLink(activeLink) } function activateLink(hash: string | null) {