diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2023-07-08 15:30:36 +0900 |
|---|---|---|
| committer | syuilo <Syuilotan@yahoo.co.jp> | 2023-07-08 15:30:36 +0900 |
| commit | 15683370f0379360c475a9ad77bb802c43f6d181 (patch) | |
| tree | d320cbdef89b6b7bac2cb113297c311666c3aa4e | |
| parent | refactor: use esm (diff) | |
| download | misskey-15683370f0379360c475a9ad77bb802c43f6d181.tar.gz misskey-15683370f0379360c475a9ad77bb802c43f6d181.tar.bz2 misskey-15683370f0379360c475a9ad77bb802c43f6d181.zip | |
fix(frontend): ページ遷移でスクロール位置が保持されない問題を修正
Fix #11068
| -rw-r--r-- | CHANGELOG.md | 9 | ||||
| -rw-r--r-- | packages/frontend/src/components/MkPageWindow.vue | 10 | ||||
| -rw-r--r-- | packages/frontend/src/nirax.ts | 36 | ||||
| -rw-r--r-- | packages/frontend/src/router.ts | 31 | ||||
| -rw-r--r-- | packages/frontend/src/ui/deck/main-column.vue | 11 | ||||
| -rw-r--r-- | packages/frontend/src/ui/universal.vue | 3 |
6 files changed, 53 insertions, 47 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b2e54ea47..905c2ea2de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,15 +19,16 @@ - サーバーのマシン情報の公開を無効にしてパフォーマンスを向上させることができるようになりました ### Client -- Fix: サーバーメトリクスが90度傾いている -- Fix: 非ログイン時にクレデンシャルが必要なページに行くとエラーが出る問題を修正 -- Fix: sparkle内にリンクを入れるとクリック不能になる問題の修正 -- Fix: ZenUIでポップアップの表示位置がおかしい問題を修正 - deck UIのカラムのメニューからアンテナとリストの編集画面を開けるように - ドライブファイルのメニューで画像をクロップできるように - 画像を動画と同様に簡単に隠せるように - オリジナル画像を保持せずにアップロードする場合webpでアップロードされるように(Safari以外) - 見たことのあるRenoteを省略して表示をオンのときに自分のnoteのrenoteを省略するように +- Fix: サーバーメトリクスが90度傾いている +- Fix: 非ログイン時にクレデンシャルが必要なページに行くとエラーが出る問題を修正 +- Fix: sparkle内にリンクを入れるとクリック不能になる問題の修正 +- Fix: ZenUIでポップアップの表示位置がおかしい問題を修正 +- Fix: ページ遷移でスクロール位置が保持されない問題を修正 ### Server - JSON.parse の回数を削減することで、ストリーミングのパフォーマンスを向上しました diff --git a/packages/frontend/src/components/MkPageWindow.vue b/packages/frontend/src/components/MkPageWindow.vue index 08de5622f5..6318a9fd70 100644 --- a/packages/frontend/src/components/MkPageWindow.vue +++ b/packages/frontend/src/components/MkPageWindow.vue @@ -17,14 +17,14 @@ </template> </template> - <div :class="$style.root" style="container-type: inline-size;"> + <div ref="contents" :class="$style.root" style="container-type: inline-size;"> <RouterView :key="reloadCount" :router="router"/> </div> </MkWindow> </template> <script lang="ts" setup> -import { ComputedRef, onMounted, onUnmounted, provide } from 'vue'; +import { ComputedRef, onMounted, onUnmounted, provide, shallowRef } from 'vue'; import RouterView from '@/components/global/RouterView.vue'; import MkWindow from '@/components/MkWindow.vue'; import { popout as _popout } from '@/scripts/popout'; @@ -32,11 +32,12 @@ import copyToClipboard from '@/scripts/copy-to-clipboard'; import { url } from '@/config'; import { mainRouter, routes, page } from '@/router'; import { $i } from '@/account'; -import { Router } from '@/nirax'; +import { Router, useScrollPositionManager } from '@/nirax'; import { i18n } from '@/i18n'; import { PageMetadata, provideMetadataReceiver } from '@/scripts/page-metadata'; import { openingWindowsCount } from '@/os'; import { claimAchievement } from '@/scripts/achievements'; +import { getScrollContainer } from '@/scripts/scroll'; const props = defineProps<{ initialPath: string; @@ -48,6 +49,7 @@ defineEmits<{ const router = new Router(routes, props.initialPath, !!$i, page(() => import('@/pages/not-found.vue'))); +const contents = shallowRef<HTMLElement>(); let pageMetadata = $ref<null | ComputedRef<PageMetadata>>(); let windowEl = $shallowRef<InstanceType<typeof MkWindow>>(); const history = $ref<{ path: string; key: any; }[]>([{ @@ -139,6 +141,8 @@ function popout() { windowEl.close(); } +useScrollPositionManager(() => getScrollContainer(contents.value), router); + onMounted(() => { openingWindowsCount.value++; if (openingWindowsCount.value >= 3) { diff --git a/packages/frontend/src/nirax.ts b/packages/frontend/src/nirax.ts index 3fa6bd55e2..3a03444de2 100644 --- a/packages/frontend/src/nirax.ts +++ b/packages/frontend/src/nirax.ts @@ -1,7 +1,7 @@ // NIRAX --- A lightweight router import { EventEmitter } from 'eventemitter3'; -import { Component, shallowRef, ShallowRef } from 'vue'; +import { Component, onMounted, shallowRef, ShallowRef } from 'vue'; import { safeURIDecode } from '@/scripts/safe-uri-decode'; type RouteDef = { @@ -267,13 +267,33 @@ export class Router extends EventEmitter<{ }); } - public replace(path: string, key?: string | null, emitEvent = true) { + public replace(path: string, key?: string | null) { this.navigate(path, key); - if (emitEvent) { - this.emit('replace', { - path, - key: this.currentKey, - }); - } } } + +export function useScrollPositionManager(getScrollContainer: () => HTMLElement, router: Router) { + const scrollPosStore = new Map<string, number>(); + + onMounted(() => { + const scrollContainer = getScrollContainer(); + + scrollContainer.addEventListener('scroll', () => { + scrollPosStore.set(router.getCurrentKey(), scrollContainer.scrollTop); + }, { passive: true }); + + router.addListener('change', ctx => { + const scrollPos = scrollPosStore.get(ctx.key) ?? 0; + scrollContainer.scroll({ top: scrollPos, behavior: 'instant' }); + if (scrollPos !== 0) { + window.setTimeout(() => { // 遷移直後はタイミングによってはコンポーネントが復元し切ってない可能性も考えられるため少し時間を空けて再度スクロール + scrollContainer.scroll({ top: scrollPos, behavior: 'instant' }); + }, 100); + } + }); + + router.addListener('same', () => { + scrollContainer.scroll({ top: 0, behavior: 'smooth' }); + }); + }); +} diff --git a/packages/frontend/src/router.ts b/packages/frontend/src/router.ts index 8540d4320f..873b372e0a 100644 --- a/packages/frontend/src/router.ts +++ b/packages/frontend/src/router.ts @@ -509,41 +509,12 @@ export const mainRouter = new Router(routes, location.pathname + location.search window.history.replaceState({ key: mainRouter.getCurrentKey() }, '', location.href); -// TODO: このファイルでスクロール位置も管理する設計だとdeckに対応できないのでなんとかする -// スクロール位置取得+スクロール位置設定関数をprovideする感じでも良いかも - -const scrollPosStore = new Map<string, number>(); - -window.setInterval(() => { - scrollPosStore.set(window.history.state?.key, window.scrollY); -}, 1000); - mainRouter.addListener('push', ctx => { window.history.pushState({ key: ctx.key }, '', ctx.path); - const scrollPos = scrollPosStore.get(ctx.key) ?? 0; - window.scroll({ top: scrollPos, behavior: 'instant' }); - if (scrollPos !== 0) { - window.setTimeout(() => { // 遷移直後はタイミングによってはコンポーネントが復元し切ってない可能性も考えられるため少し時間を空けて再度スクロール - window.scroll({ top: scrollPos, behavior: 'instant' }); - }, 100); - } -}); - -mainRouter.addListener('replace', ctx => { - window.history.replaceState({ key: ctx.key }, '', ctx.path); -}); - -mainRouter.addListener('same', () => { - window.scroll({ top: 0, behavior: 'smooth' }); }); window.addEventListener('popstate', (event) => { - mainRouter.replace(location.pathname + location.search + location.hash, event.state?.key, false); - const scrollPos = scrollPosStore.get(event.state?.key) ?? 0; - window.scroll({ top: scrollPos, behavior: 'instant' }); - window.setTimeout(() => { // 遷移直後はタイミングによってはコンポーネントが復元し切ってない可能性も考えられるため少し時間を空けて再度スクロール - window.scroll({ top: scrollPos, behavior: 'instant' }); - }, 100); + mainRouter.replace(location.pathname + location.search + location.hash, event.state?.key); }); export function useRouter(): Router { diff --git a/packages/frontend/src/ui/deck/main-column.vue b/packages/frontend/src/ui/deck/main-column.vue index 169fac70a2..0413307955 100644 --- a/packages/frontend/src/ui/deck/main-column.vue +++ b/packages/frontend/src/ui/deck/main-column.vue @@ -7,24 +7,29 @@ </template> </template> - <RouterView @contextmenu.stop="onContextmenu"/> + <div ref="contents"> + <RouterView @contextmenu.stop="onContextmenu"/> + </div> </XColumn> </template> <script lang="ts" setup> -import { ComputedRef, provide } from 'vue'; +import { ComputedRef, provide, shallowRef } from 'vue'; import XColumn from './column.vue'; import { deckStore, Column } from '@/ui/deck/deck-store'; import * as os from '@/os'; import { i18n } from '@/i18n'; import { mainRouter } from '@/router'; import { PageMetadata, provideMetadataReceiver } from '@/scripts/page-metadata'; +import { useScrollPositionManager } from '@/nirax'; +import { getScrollContainer } from '@/scripts/scroll'; defineProps<{ column: Column; isStacked: boolean; }>(); +const contents = shallowRef<HTMLElement>(); let pageMetadata = $ref<null | ComputedRef<PageMetadata>>(); provide('router', mainRouter); @@ -61,4 +66,6 @@ function onContextmenu(ev: MouseEvent) { }, }], ev); } + +useScrollPositionManager(() => getScrollContainer(contents.value), mainRouter); </script> diff --git a/packages/frontend/src/ui/universal.vue b/packages/frontend/src/ui/universal.vue index 8abb20300f..9ae43c39d3 100644 --- a/packages/frontend/src/ui/universal.vue +++ b/packages/frontend/src/ui/universal.vue @@ -95,6 +95,7 @@ import { PageMetadata, provideMetadataReceiver } from '@/scripts/page-metadata'; import { deviceKind } from '@/scripts/device-kind'; import { miLocalStorage } from '@/local-storage'; import { CURRENT_STICKY_BOTTOM } from '@/const'; +import { useScrollPositionManager } from '@/nirax'; const XWidgets = defineAsyncComponent(() => import('./universal.widgets.vue')); const XSidebar = defineAsyncComponent(() => import('@/ui/_common_/navbar.vue')); @@ -213,6 +214,8 @@ watch($$(navFooter), () => { }, { immediate: true, }); + +useScrollPositionManager(() => contents.value.rootEl, mainRouter); </script> <style> |