summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsyuilo <4439005+syuilo@users.noreply.github.com>2025-04-15 20:33:04 +0900
committersyuilo <4439005+syuilo@users.noreply.github.com>2025-04-15 20:33:04 +0900
commitee29f31324ca3b0513325cbb14b25a59e6485d23 (patch)
tree92cfa59aa4a4792b18509c24c5eeb3ca60e4ee33
parentBump version to 2025.4.1-alpha.0 (diff)
downloadmisskey-ee29f31324ca3b0513325cbb14b25a59e6485d23.tar.gz
misskey-ee29f31324ca3b0513325cbb14b25a59e6485d23.tar.bz2
misskey-ee29f31324ca3b0513325cbb14b25a59e6485d23.zip
fix(frontend): make keep scroll pos of timeline
-rw-r--r--CHANGELOG.md1
-rw-r--r--packages/frontend/src/use/use-scroll-position-keeper.ts58
2 files changed, 59 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 97c754a86b..693b31c44a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@
- Fix: ログアウトした際に処理が終了しない問題を修正
- Fix: 自動バックアップが設定されている環境でログアウト直前に設定をバックアップするように
- Fix: フォルダを開いた状態でメニューからアップロードしてもルートフォルダにアップロードされる問題を修正 #15836
+- Fix: タイムラインのスクロール位置を記憶するように修正
### Server
- Enhance: フォローしているユーザーならフォロワー限定投稿のノートでもアンテナで検知できるように
diff --git a/packages/frontend/src/use/use-scroll-position-keeper.ts b/packages/frontend/src/use/use-scroll-position-keeper.ts
new file mode 100644
index 0000000000..00cc51a459
--- /dev/null
+++ b/packages/frontend/src/use/use-scroll-position-keeper.ts
@@ -0,0 +1,58 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { throttle } from 'throttle-debounce';
+import { nextTick, onActivated, 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;
+
+ watch(scrollContainerRef, (el) => {
+ if (!el) return;
+
+ const onScroll = () => {
+ if (!el) return;
+ const scrollContainerRect = el.getBoundingClientRect();
+ const viewPosition = scrollContainerRect.height / 2;
+
+ const anchorEls = el.querySelectorAll('[data-scroll-anchor]');
+ for (let i = anchorEls.length - 1; i > -1; i--) { // 下から見た方が速い
+ const anchorEl = anchorEls[i] as HTMLElement;
+ const anchorRect = anchorEl.getBoundingClientRect();
+ const anchorTop = anchorRect.top;
+ const anchorBottom = anchorRect.bottom;
+ if (anchorTop <= viewPosition && anchorBottom >= viewPosition) {
+ anchorId = anchorEl.getAttribute('data-scroll-anchor');
+ break;
+ }
+ }
+ };
+
+ // ほんとはscrollイベントじゃなくてonBeforeDeactivatedでやりたい
+ // https://github.com/vuejs/vue/issues/9454
+ // https://github.com/vuejs/rfcs/pull/284
+ el.addEventListener('scroll', throttle(1000, onScroll), { passive: true });
+ }, {
+ immediate: true,
+ });
+
+ onActivated(() => {
+ 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',
+ });
+ });
+ });
+}