Skip to content
This repository was archived by the owner on Jan 16, 2026. It is now read-only.

Commit ee29f31

Browse files
committed
fix(frontend): make keep scroll pos of timeline
1 parent f5a89c2 commit ee29f31

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
- Fix: ログアウトした際に処理が終了しない問題を修正
1010
- Fix: 自動バックアップが設定されている環境でログアウト直前に設定をバックアップするように
1111
- Fix: フォルダを開いた状態でメニューからアップロードしてもルートフォルダにアップロードされる問題を修正 #15836
12+
- Fix: タイムラインのスクロール位置を記憶するように修正
1213

1314
### Server
1415
- Enhance: フォローしているユーザーならフォロワー限定投稿のノートでもアンテナで検知できるように
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* SPDX-FileCopyrightText: syuilo and misskey-project
3+
* SPDX-License-Identifier: AGPL-3.0-only
4+
*/
5+
6+
import { throttle } from 'throttle-debounce';
7+
import { nextTick, onActivated, onUnmounted, watch } from 'vue';
8+
import type { Ref } from 'vue';
9+
10+
// note render skippingがオンだとズレるため、遷移直前にスクロール範囲に表示されているdata-scroll-anchor要素を特定して、復元時に当該要素までスクロールするようにする
11+
12+
export function useScrollPositionKeeper(scrollContainerRef: Ref<HTMLElement | null | undefined>): void {
13+
let anchorId: string | null = null;
14+
15+
watch(scrollContainerRef, (el) => {
16+
if (!el) return;
17+
18+
const onScroll = () => {
19+
if (!el) return;
20+
const scrollContainerRect = el.getBoundingClientRect();
21+
const viewPosition = scrollContainerRect.height / 2;
22+
23+
const anchorEls = el.querySelectorAll('[data-scroll-anchor]');
24+
for (let i = anchorEls.length - 1; i > -1; i--) { // 下から見た方が速い
25+
const anchorEl = anchorEls[i] as HTMLElement;
26+
const anchorRect = anchorEl.getBoundingClientRect();
27+
const anchorTop = anchorRect.top;
28+
const anchorBottom = anchorRect.bottom;
29+
if (anchorTop <= viewPosition && anchorBottom >= viewPosition) {
30+
anchorId = anchorEl.getAttribute('data-scroll-anchor');
31+
break;
32+
}
33+
}
34+
};
35+
36+
// ほんとはscrollイベントじゃなくてonBeforeDeactivatedでやりたい
37+
// https://github.com/vuejs/vue/issues/9454
38+
// https://github.com/vuejs/rfcs/pull/284
39+
el.addEventListener('scroll', throttle(1000, onScroll), { passive: true });
40+
}, {
41+
immediate: true,
42+
});
43+
44+
onActivated(() => {
45+
nextTick(() => {
46+
if (!anchorId) return;
47+
const scrollContainer = scrollContainerRef.value;
48+
if (!scrollContainer) return;
49+
const scrollAnchorEl = scrollContainer.querySelector(`[data-scroll-anchor="${anchorId}"]`);
50+
if (!scrollAnchorEl) return;
51+
scrollAnchorEl.scrollIntoView({
52+
behavior: 'instant',
53+
block: 'center',
54+
inline: 'center',
55+
});
56+
});
57+
});
58+
}

0 commit comments

Comments
 (0)