nuxt
Version:
61 lines (60 loc) • 2.06 kB
JavaScript
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
};
}