100 lines
2.9 KiB
Vue
100 lines
2.9 KiB
Vue
<template>
|
|
<KeepAlive :max="defaultStore.state.numberOfPageCache">
|
|
<Suspense :timeout="0">
|
|
<component :is="currentPageComponent" :key="key" v-bind="Object.fromEntries(currentPageProps)"/>
|
|
|
|
<template #fallback>
|
|
<MkLoading/>
|
|
</template>
|
|
</Suspense>
|
|
</KeepAlive>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { computed, inject, onBeforeUnmount, provide, nextTick } from 'vue';
|
|
import { NiraxChangeEvent, Resolved, Router } from '@/nirax';
|
|
import { defaultStore } from '@/store';
|
|
import { getScrollContainer } from '@/scripts/scroll';
|
|
|
|
const props = defineProps<{
|
|
router?: Router;
|
|
|
|
/**
|
|
* Set any element if scroll position management needed
|
|
*/
|
|
scrollContainer?: HTMLElement | null;
|
|
}>();
|
|
|
|
const router = props.router ?? inject('router');
|
|
|
|
if (router == null) {
|
|
throw new Error('no router provided');
|
|
}
|
|
|
|
const currentDepth = inject('routerCurrentDepth', 0);
|
|
provide('routerCurrentDepth', currentDepth + 1);
|
|
|
|
function resolveNested(current: Resolved, d = 0): Resolved | null {
|
|
if (d === currentDepth) {
|
|
return current;
|
|
} else {
|
|
if (current.child) {
|
|
return resolveNested(current.child, d + 1);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
const current = resolveNested(router.current)!;
|
|
let currentPageComponent = $shallowRef(current.route.component);
|
|
let currentPageProps = $ref(current.props);
|
|
let key = $ref(current.route.path + JSON.stringify(Object.fromEntries(current.props)));
|
|
|
|
const scrollContainer = computed(() => props.scrollContainer ? (getScrollContainer(props.scrollContainer) ?? document.getElementsByTagName('html')[0]) : undefined);
|
|
|
|
const scrollPosStore = new Map<string, number>();
|
|
|
|
function onChange(ctx: NiraxChangeEvent) {
|
|
// save scroll position
|
|
if (scrollContainer.value) scrollPosStore.set(key, scrollContainer.value.scrollTop);
|
|
|
|
//#region change page
|
|
const current = resolveNested(ctx.resolved);
|
|
if (current == null) return;
|
|
currentPageComponent = current.route.component;
|
|
currentPageProps = current.props;
|
|
key = current.route.path + JSON.stringify(Object.fromEntries(current.props));
|
|
//#endregion
|
|
|
|
//#region scroll
|
|
nextTick(() => {
|
|
if (!scrollContainer.value) return;
|
|
|
|
const scrollPos = scrollPosStore.get(key) ?? 0;
|
|
scrollContainer.value.scroll({ top: scrollPos, behavior: 'instant' });
|
|
if (scrollPos !== 0) {
|
|
window.setTimeout(() => { // 遷移直後はタイミングによってはコンポーネントが復元し切ってない可能性も考えられるため少し時間を空けて再度スクロール
|
|
if (!scrollContainer.value) return;
|
|
scrollContainer.value.scroll({ top: scrollPos, behavior: 'instant' });
|
|
}, 100);
|
|
}
|
|
});
|
|
//#endregion
|
|
}
|
|
|
|
router.addListener('change', onChange);
|
|
|
|
function onSame() {
|
|
if (!scrollContainer.value) return;
|
|
scrollContainer.value.scroll({ top: 0, behavior: 'smooth' });
|
|
}
|
|
|
|
router.addListener('same', onSame);
|
|
|
|
onBeforeUnmount(() => {
|
|
router.removeListener('change', onChange);
|
|
router.removeListener('same', onSame);
|
|
});
|
|
</script>
|