From 86e2a6f97287c0999090d5af0e8362f3e48884db Mon Sep 17 00:00:00 2001 From: Evan You Date: Wed, 15 Mar 2023 17:50:24 +0800 Subject: [PATCH] feat: support multiple selectors for scrollOffset --- src/client/app/router.ts | 26 ++++++++++++++++++++++---- src/node/config.ts | 6 +++++- types/shared.d.ts | 2 +- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/client/app/router.ts b/src/client/app/router.ts index 4b565d194988..7c91404ddffa 100644 --- a/src/client/app/router.ts +++ b/src/client/app/router.ts @@ -241,10 +241,20 @@ export function scrollTo(el: Element, hash: string, smooth = false) { } if (target) { - let offset = siteDataRef.value.scrollOffset - if (typeof offset === 'string') { - offset = - document.querySelector(offset)!.getBoundingClientRect().bottom + 24 + const scrollOffset = siteDataRef.value.scrollOffset + let offset: number = 0 + if (typeof scrollOffset === 'number') { + offset = scrollOffset + } else if (typeof scrollOffset === 'string') { + offset = tryOffsetSelector(scrollOffset) + } else if (Array.isArray(scrollOffset)) { + for (const selector of scrollOffset) { + const res = tryOffsetSelector(selector) + if (res) { + offset = res + break + } + } } const targetPadding = parseInt( window.getComputedStyle(target).paddingTop, @@ -268,6 +278,14 @@ export function scrollTo(el: Element, hash: string, smooth = false) { } } +function tryOffsetSelector(selector: string): number { + const el = document.querySelector(selector) + if (!el) return 0 + const bot = el.getBoundingClientRect().bottom + if (bot < 0) return 0 + return bot + 24 +} + function handleHMR(route: Route): void { // update route.data on HMR updates of active page if (import.meta.hot) { diff --git a/src/node/config.ts b/src/node/config.ts index 26667380fa7b..763aea034f74 100644 --- a/src/node/config.ts +++ b/src/node/config.ts @@ -67,8 +67,12 @@ export interface UserConfig /** * Configure the scroll offset when the theme has a sticky header. * Can be a number or a selector element to get the offset from. + * Can also be an array of selectors in case some elements will be + * invisible due to responsive layout. VitePress will fallback to the next + * selector if a selector fails to match, or the matched element is not + * currently visible in viewport. */ - scrollOffset?: number | string + scrollOffset?: number | string | string[] /** * Enable MPA / zero-JS mode. diff --git a/types/shared.d.ts b/types/shared.d.ts index 35f3fbee9b8a..9d5cff80d8ab 100644 --- a/types/shared.d.ts +++ b/types/shared.d.ts @@ -56,7 +56,7 @@ export interface SiteData { head: HeadConfig[] appearance: boolean | 'dark' themeConfig: ThemeConfig - scrollOffset: number | string + scrollOffset: number | string | string[] locales: LocaleConfig localeIndex?: string }