2023-04-07 16:02:47 +00:00
|
|
|
import type { RouteLocationNormalized, RouterScrollBehavior } from 'vue-router'
|
2022-10-19 12:43:03 +00:00
|
|
|
import { nextTick } from 'vue'
|
2023-02-13 22:42:04 +00:00
|
|
|
import type { RouterConfig } from 'nuxt/schema'
|
2023-02-09 06:26:41 +00:00
|
|
|
import { useNuxtApp } from '#app/nuxt'
|
2023-04-14 12:53:21 +00:00
|
|
|
// @ts-expect-error virtual file
|
2022-11-04 18:09:28 +00:00
|
|
|
import { appPageTransition as defaultPageTransition } from '#build/nuxt.config.mjs'
|
2022-10-19 12:43:03 +00:00
|
|
|
|
|
|
|
type ScrollPosition = Awaited<ReturnType<RouterScrollBehavior>>
|
|
|
|
|
|
|
|
// Default router options
|
|
|
|
// https://router.vuejs.org/api/#routeroptions
|
|
|
|
export default <RouterConfig> {
|
|
|
|
scrollBehavior (to, from, savedPosition) {
|
|
|
|
const nuxtApp = useNuxtApp()
|
|
|
|
|
|
|
|
// By default when the returned position is falsy or an empty object, vue-router will retain the current scroll position
|
|
|
|
// savedPosition is only available for popstate navigations (back button)
|
|
|
|
let position: ScrollPosition = savedPosition || undefined
|
|
|
|
|
|
|
|
// Scroll to top if route is changed by default
|
2022-10-19 14:33:01 +00:00
|
|
|
if (!position && from && to && to.meta.scrollToTop !== false && _isDifferentRoute(from, to)) {
|
2022-10-19 12:43:03 +00:00
|
|
|
position = { left: 0, top: 0 }
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hash routes on the same page, no page hook is fired so resolve here
|
2022-10-21 08:27:40 +00:00
|
|
|
if (to.path === from.path) {
|
2022-10-19 12:43:03 +00:00
|
|
|
if (from.hash && !to.hash) {
|
|
|
|
return { left: 0, top: 0 }
|
|
|
|
}
|
|
|
|
if (to.hash) {
|
|
|
|
return { el: to.hash, top: _getHashElementScrollMarginTop(to.hash) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wait for `page:transition:finish` or `page:finish` depending on if transitions are enabled or not
|
2022-11-04 18:09:28 +00:00
|
|
|
const hasTransition = (route: RouteLocationNormalized) => !!(route.meta.pageTransition ?? defaultPageTransition)
|
|
|
|
const hookToWait = (hasTransition(from) && hasTransition(to)) ? 'page:transition:finish' : 'page:finish'
|
2022-10-19 12:43:03 +00:00
|
|
|
return new Promise((resolve) => {
|
|
|
|
nuxtApp.hooks.hookOnce(hookToWait, async () => {
|
|
|
|
await nextTick()
|
|
|
|
if (to.hash) {
|
|
|
|
position = { el: to.hash, top: _getHashElementScrollMarginTop(to.hash) }
|
|
|
|
}
|
|
|
|
resolve(position)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function _getHashElementScrollMarginTop (selector: string): number {
|
2022-11-09 09:10:32 +00:00
|
|
|
try {
|
|
|
|
const elem = document.querySelector(selector)
|
|
|
|
if (elem) {
|
|
|
|
return parseFloat(getComputedStyle(elem).scrollMarginTop)
|
|
|
|
}
|
|
|
|
} catch {}
|
2022-10-19 12:43:03 +00:00
|
|
|
return 0
|
|
|
|
}
|
2022-10-19 14:33:01 +00:00
|
|
|
|
|
|
|
function _isDifferentRoute (a: RouteLocationNormalized, b: RouteLocationNormalized): boolean {
|
|
|
|
const samePageComponent = a.matched[0] === b.matched[0]
|
|
|
|
if (!samePageComponent) {
|
|
|
|
return true
|
|
|
|
}
|
2022-10-19 15:31:05 +00:00
|
|
|
if (samePageComponent && JSON.stringify(a.params) !== JSON.stringify(b.params)) {
|
2022-10-19 14:33:01 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|