UNPKG

nuxt

Version:

Nuxt is a free and open-source framework with an intuitive and extendable way to create type-safe, performant and production-grade full-stack web applications and websites with Vue.js.

61 lines (60 loc) 2.06 kB
import { START_LOCATION } from "vue-router"; import { useNuxtApp } from "#app/nuxt"; import { isChangingPage } from "#app/components/utils"; import { useRouter } from "#app/composables/router"; export default { scrollBehavior(to, from, savedPosition) { const nuxtApp = useNuxtApp(); const hashScrollBehaviour = useRouter().options?.scrollBehaviorType ?? "auto"; if (to.path === from.path) { if (from.hash && !to.hash) { return { left: 0, top: 0 }; } if (to.hash) { return { el: to.hash, top: _getHashElementScrollMarginTop(to.hash), behavior: hashScrollBehaviour }; } return false; } const routeAllowsScrollToTop = typeof to.meta.scrollToTop === "function" ? to.meta.scrollToTop(to, from) : to.meta.scrollToTop; if (routeAllowsScrollToTop === false) { return false; } const hookToWait = nuxtApp._runningTransition ? "page:transition:finish" : "page:loading:end"; return new Promise((resolve) => { if (from === START_LOCATION) { resolve(_calculatePosition(to, from, savedPosition, hashScrollBehaviour)); return; } nuxtApp.hooks.hookOnce(hookToWait, () => { requestAnimationFrame(() => resolve(_calculatePosition(to, from, savedPosition, hashScrollBehaviour))); }); }); } }; function _getHashElementScrollMarginTop(selector) { try { const elem = document.querySelector(selector); if (elem) { return (Number.parseFloat(getComputedStyle(elem).scrollMarginTop) || 0) + (Number.parseFloat(getComputedStyle(document.documentElement).scrollPaddingTop) || 0); } } catch { } return 0; } function _calculatePosition(to, from, savedPosition, defaultHashScrollBehaviour) { if (savedPosition) { return savedPosition; } const isPageNavigation = isChangingPage(to, from); if (to.hash) { return { el: to.hash, top: _getHashElementScrollMarginTop(to.hash), behavior: isPageNavigation ? defaultHashScrollBehaviour : "instant" }; } return { left: 0, top: 0 }; }