fix(nuxt): wait for `page:finish` hook in CSR before scrolling to hash on page enter

This commit is contained in:
Damian Glowala 2024-09-14 10:31:16 +02:00
parent f7c68ac0f6
commit d8d89b9dee
1 changed files with 12 additions and 7 deletions

View File

@ -29,25 +29,28 @@ export default <RouterConfig> {
// Hash routes on the same page, no page hook is fired so resolve here // Hash routes on the same page, no page hook is fired so resolve here
if (to.path === from.path) { if (to.path === from.path) {
if (from.hash && !to.hash) { if (!to.hash) {
return { left: 0, top: 0 } if (from.hash) {
return { left: 0, top: 0 }
}
// The route isn't changing so keep current scroll position
return false
} }
if (to.hash) {
return { el: to.hash, top: _getHashElementScrollMarginTop(to.hash), behavior }
}
// The route isn't changing so keep current scroll position
return false
} }
// Wait for `page:transition:finish` or `page:finish` depending on if transitions are enabled or not // Wait for `page:transition:finish` or `page:finish` depending on if transitions are enabled or not
const hasTransition = (route: RouteLocationNormalized) => !!(route.meta.pageTransition ?? defaultPageTransition) const hasTransition = (route: RouteLocationNormalized) => !!(route.meta.pageTransition ?? defaultPageTransition)
const hookToWait = (hasTransition(from) && hasTransition(to)) ? 'page:transition:finish' : 'page:finish' const hookToWait = (hasTransition(from) && hasTransition(to)) ? 'page:transition:finish' : 'page:finish'
return new Promise((resolve) => { return new Promise((resolve) => {
nuxtApp.hooks.hookOnce(hookToWait, async () => { nuxtApp.hooks.hookOnce(hookToWait, async () => {
await new Promise(resolve => setTimeout(resolve, 0)) await new Promise(resolve => setTimeout(resolve, 0))
if (to.hash) { if (to.hash) {
position = { el: to.hash, top: _getHashElementScrollMarginTop(to.hash), behavior } position = { el: to.hash, top: _getHashElementScrollMarginTop(to.hash), behavior }
} }
resolve(position) resolve(position)
}) })
}) })
@ -57,11 +60,13 @@ export default <RouterConfig> {
function _getHashElementScrollMarginTop (selector: string): number { function _getHashElementScrollMarginTop (selector: string): number {
try { try {
const elem = document.querySelector(selector) const elem = document.querySelector(selector)
if (elem) { if (elem) {
return (Number.parseFloat(getComputedStyle(elem).scrollMarginTop) || 0) + (Number.parseFloat(getComputedStyle(document.documentElement).scrollPaddingTop) || 0) return (Number.parseFloat(getComputedStyle(elem).scrollMarginTop) || 0) + (Number.parseFloat(getComputedStyle(document.documentElement).scrollPaddingTop) || 0)
} }
} catch { } catch {
// ignore any errors parsing scrollMarginTop // ignore any errors parsing scrollMarginTop
} }
return 0 return 0
} }