diff options
| author | syuilo <4439005+syuilo@users.noreply.github.com> | 2025-04-16 10:35:05 +0900 |
|---|---|---|
| committer | syuilo <4439005+syuilo@users.noreply.github.com> | 2025-04-16 10:35:05 +0900 |
| commit | 6d90e09a587e000fb780f64dae4a1d249568dbc3 (patch) | |
| tree | 0b784902ef30797b598d48af2d452d1fbea3af5b /packages/frontend/src | |
| parent | Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop (diff) | |
| download | sharkey-6d90e09a587e000fb780f64dae4a1d249568dbc3.tar.gz sharkey-6d90e09a587e000fb780f64dae4a1d249568dbc3.tar.bz2 sharkey-6d90e09a587e000fb780f64dae4a1d249568dbc3.zip | |
enhance(frontend): タイムライン以外でもスクロール位置の保持を試みるように
Diffstat (limited to 'packages/frontend/src')
3 files changed, 33 insertions, 13 deletions
diff --git a/packages/frontend/src/components/MkNotifications.vue b/packages/frontend/src/components/MkNotifications.vue index 99eca35eb7..b8fada1020 100644 --- a/packages/frontend/src/components/MkNotifications.vue +++ b/packages/frontend/src/components/MkNotifications.vue @@ -24,8 +24,8 @@ SPDX-License-Identifier: AGPL-3.0-only tag="div" > <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"/> - <XNotification v-else :class="$style.item" :notification="notification" :withTime="true" :full="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" :data-scroll-anchor="notification.id"/> </template> </component> </template> diff --git a/packages/frontend/src/components/global/PageWithHeader.vue b/packages/frontend/src/components/global/PageWithHeader.vue index 7ea0b5c97f..99f8df0780 100644 --- a/packages/frontend/src/components/global/PageWithHeader.vue +++ b/packages/frontend/src/components/global/PageWithHeader.vue @@ -20,6 +20,7 @@ import { useTemplateRef } from 'vue'; import { scrollInContainer } from '@@/js/scroll.js'; import type { PageHeaderItem } from '@/types/page-header.js'; import type { Tab } from './MkPageHeader.tabs.vue'; +import { useScrollPositionKeeper } from '@/use/use-scroll-position-keeper.js'; const props = withDefaults(defineProps<{ tabs?: Tab[]; @@ -35,6 +36,8 @@ const props = withDefaults(defineProps<{ const tab = defineModel<string>('tab'); const rootEl = useTemplateRef('rootEl'); +useScrollPositionKeeper(rootEl); + defineExpose({ scrollToTop: () => { if (rootEl.value) scrollInContainer(rootEl.value, { top: 0, behavior: 'smooth' }); diff --git a/packages/frontend/src/use/use-scroll-position-keeper.ts b/packages/frontend/src/use/use-scroll-position-keeper.ts index 00cc51a459..f7b3015cc9 100644 --- a/packages/frontend/src/use/use-scroll-position-keeper.ts +++ b/packages/frontend/src/use/use-scroll-position-keeper.ts @@ -4,19 +4,22 @@ */ 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'; // note render skippingがオンだとズレるため、遷移直前にスクロール範囲に表示されているdata-scroll-anchor要素を特定して、復元時に当該要素までスクロールするようにする export function useScrollPositionKeeper(scrollContainerRef: Ref<HTMLElement | null | undefined>): void { let anchorId: string | null = null; + let ready = true; watch(scrollContainerRef, (el) => { if (!el) return; const onScroll = () => { if (!el) return; + if (!ready) return; + const scrollContainerRect = el.getBoundingClientRect(); const viewPosition = scrollContainerRect.height / 2; @@ -41,18 +44,32 @@ export function useScrollPositionKeeper(scrollContainerRef: Ref<HTMLElement | nu immediate: true, }); + const restore = () => { + if (!anchorId) return; + const scrollContainer = scrollContainerRef.value; + if (!scrollContainer) return; + const scrollAnchorEl = scrollContainer.querySelector(`[data-scroll-anchor="${anchorId}"]`); + if (!scrollAnchorEl) return; + scrollAnchorEl.scrollIntoView({ + behavior: 'instant', + block: 'center', + inline: 'center', + }); + }; + + onDeactivated(() => { + ready = false; + }); + onActivated(() => { + restore(); nextTick(() => { - if (!anchorId) return; - const scrollContainer = scrollContainerRef.value; - if (!scrollContainer) return; - const scrollAnchorEl = scrollContainer.querySelector(`[data-scroll-anchor="${anchorId}"]`); - if (!scrollAnchorEl) return; - scrollAnchorEl.scrollIntoView({ - behavior: 'instant', - block: 'center', - inline: 'center', - }); + restore(); + window.setTimeout(() => { + restore(); + + ready = true; + }, 100); }); }); } |