enhance(frontend): タイムライン以外でもスクロール位置の保持を試みるように
This commit is contained in:
parent
35d4b43c95
commit
6d90e09a58
|
@ -24,8 +24,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
tag="div"
|
tag="div"
|
||||||
>
|
>
|
||||||
<template v-for="(notification, i) in notifications" :key="notification.id">
|
<template v-for="(notification, i) in notifications" :key="notification.id">
|
||||||
<MkNote v-if="['reply', 'quote', 'mention'].includes(notification.type)" :class="$style.item" :note="notification.note" :withHardMute="true"/>
|
<MkNote v-if="['reply', 'quote', 'mention'].includes(notification.type)" :class="$style.item" :note="notification.note" :withHardMute="true" :data-scroll-anchor="notification.id"/>
|
||||||
<XNotification v-else :class="$style.item" :notification="notification" :withTime="true" :full="true"/>
|
<XNotification v-else :class="$style.item" :notification="notification" :withTime="true" :full="true" :data-scroll-anchor="notification.id"/>
|
||||||
</template>
|
</template>
|
||||||
</component>
|
</component>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { useTemplateRef } from 'vue';
|
||||||
import { scrollInContainer } from '@@/js/scroll.js';
|
import { scrollInContainer } from '@@/js/scroll.js';
|
||||||
import type { PageHeaderItem } from '@/types/page-header.js';
|
import type { PageHeaderItem } from '@/types/page-header.js';
|
||||||
import type { Tab } from './MkPageHeader.tabs.vue';
|
import type { Tab } from './MkPageHeader.tabs.vue';
|
||||||
|
import { useScrollPositionKeeper } from '@/use/use-scroll-position-keeper.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
tabs?: Tab[];
|
tabs?: Tab[];
|
||||||
|
@ -35,6 +36,8 @@ const props = withDefaults(defineProps<{
|
||||||
const tab = defineModel<string>('tab');
|
const tab = defineModel<string>('tab');
|
||||||
const rootEl = useTemplateRef('rootEl');
|
const rootEl = useTemplateRef('rootEl');
|
||||||
|
|
||||||
|
useScrollPositionKeeper(rootEl);
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
scrollToTop: () => {
|
scrollToTop: () => {
|
||||||
if (rootEl.value) scrollInContainer(rootEl.value, { top: 0, behavior: 'smooth' });
|
if (rootEl.value) scrollInContainer(rootEl.value, { top: 0, behavior: 'smooth' });
|
||||||
|
|
|
@ -4,19 +4,22 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { throttle } from 'throttle-debounce';
|
import { throttle } from 'throttle-debounce';
|
||||||
import { nextTick, onActivated, onUnmounted, watch } from 'vue';
|
import { nextTick, onActivated, onDeactivated, onUnmounted, watch } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
|
|
||||||
// note render skippingがオンだとズレるため、遷移直前にスクロール範囲に表示されているdata-scroll-anchor要素を特定して、復元時に当該要素までスクロールするようにする
|
// note render skippingがオンだとズレるため、遷移直前にスクロール範囲に表示されているdata-scroll-anchor要素を特定して、復元時に当該要素までスクロールするようにする
|
||||||
|
|
||||||
export function useScrollPositionKeeper(scrollContainerRef: Ref<HTMLElement | null | undefined>): void {
|
export function useScrollPositionKeeper(scrollContainerRef: Ref<HTMLElement | null | undefined>): void {
|
||||||
let anchorId: string | null = null;
|
let anchorId: string | null = null;
|
||||||
|
let ready = true;
|
||||||
|
|
||||||
watch(scrollContainerRef, (el) => {
|
watch(scrollContainerRef, (el) => {
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
|
|
||||||
const onScroll = () => {
|
const onScroll = () => {
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
|
if (!ready) return;
|
||||||
|
|
||||||
const scrollContainerRect = el.getBoundingClientRect();
|
const scrollContainerRect = el.getBoundingClientRect();
|
||||||
const viewPosition = scrollContainerRect.height / 2;
|
const viewPosition = scrollContainerRect.height / 2;
|
||||||
|
|
||||||
|
@ -41,8 +44,7 @@ export function useScrollPositionKeeper(scrollContainerRef: Ref<HTMLElement | nu
|
||||||
immediate: true,
|
immediate: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
onActivated(() => {
|
const restore = () => {
|
||||||
nextTick(() => {
|
|
||||||
if (!anchorId) return;
|
if (!anchorId) return;
|
||||||
const scrollContainer = scrollContainerRef.value;
|
const scrollContainer = scrollContainerRef.value;
|
||||||
if (!scrollContainer) return;
|
if (!scrollContainer) return;
|
||||||
|
@ -53,6 +55,21 @@ export function useScrollPositionKeeper(scrollContainerRef: Ref<HTMLElement | nu
|
||||||
block: 'center',
|
block: 'center',
|
||||||
inline: 'center',
|
inline: 'center',
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onDeactivated(() => {
|
||||||
|
ready = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
onActivated(() => {
|
||||||
|
restore();
|
||||||
|
nextTick(() => {
|
||||||
|
restore();
|
||||||
|
window.setTimeout(() => {
|
||||||
|
restore();
|
||||||
|
|
||||||
|
ready = true;
|
||||||
|
}, 100);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue