Skip to content

Commit

Permalink
fix(frontend): ページ遷移でスクロール位置が保持されない問題を修正
Browse files Browse the repository at this point in the history
Fix #11068
  • Loading branch information
syuilo committed Jul 8, 2023
1 parent 6440233 commit 1568337
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 47 deletions.
9 changes: 5 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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: ページ遷移でスクロール位置が保持されない問題を修正

This comment has been minimized.

Copy link
@jojobii-arks

jojobii-arks Jul 9, 2023

Contributor

Thank you!!! 🙇


### Server
- JSON.parse の回数を削減することで、ストリーミングのパフォーマンスを向上しました
Expand Down
10 changes: 7 additions & 3 deletions packages/frontend/src/components/MkPageWindow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,27 @@
</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';
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;
Expand All @@ -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; }[]>([{
Expand Down Expand Up @@ -139,6 +141,8 @@ function popout() {
windowEl.close();
}
useScrollPositionManager(() => getScrollContainer(contents.value), router);
onMounted(() => {
openingWindowsCount.value++;
if (openingWindowsCount.value >= 3) {
Expand Down
36 changes: 28 additions & 8 deletions packages/frontend/src/nirax.ts
Original file line number Diff line number Diff line change
@@ -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 = {
Expand Down Expand Up @@ -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' });
});
});
}
31 changes: 1 addition & 30 deletions packages/frontend/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
11 changes: 9 additions & 2 deletions packages/frontend/src/ui/deck/main-column.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -61,4 +66,6 @@ function onContextmenu(ev: MouseEvent) {
},
}], ev);
}
useScrollPositionManager(() => getScrollContainer(contents.value), mainRouter);
</script>
3 changes: 3 additions & 0 deletions packages/frontend/src/ui/universal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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'));
Expand Down Expand Up @@ -213,6 +214,8 @@ watch($$(navFooter), () => {
}, {
immediate: true,
});
useScrollPositionManager(() => contents.value.rootEl, mainRouter);
</script>
<style>
Expand Down

0 comments on commit 1568337

Please sign in to comment.