diff --git a/CHANGELOG.md b/CHANGELOG.md index 23f55c799d..ea78250e23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ - Fix: 設定変更時のリロード確認ダイアログが複数個表示されることがある問題を修正 - Fix: ファイルの詳細ページのファイルの説明で改行が正しく表示されない問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/commit/bde6bb0bd2e8b0d027e724d2acdb8ae0585a8110) +- Fix: 一部画面のページネーションが動作しにくくなっていたのを修正 ( #12766 , #11449 ) ### Server - Feat: Misskey® Reactions Buffering Technology™ (RBT)により、リアクションの作成負荷を低減することが可能に diff --git a/packages/frontend-shared/js/scroll.ts b/packages/frontend-shared/js/scroll.ts index 1062e5252f..4f2e9105c3 100644 --- a/packages/frontend-shared/js/scroll.ts +++ b/packages/frontend-shared/js/scroll.ts @@ -36,19 +36,27 @@ export function getScrollPosition(el: HTMLElement | null): number { return container == null ? window.scrollY : container.scrollTop; } -export function onScrollTop(el: HTMLElement, cb: () => unknown, tolerance = 1, once = false) { +export function onScrollTop(el: HTMLElement, cb: (topVisible: boolean) => unknown, tolerance = 1, once = false) { // とりあえず評価してみる - if (el.isConnected && isTopVisible(el)) { - cb(); + const firstTopVisible = isTopVisible(el); + if (el.isConnected && firstTopVisible) { + cb(firstTopVisible); if (once) return null; } const container = getScrollContainer(el) ?? window; + // 以下のケースにおいて、cbが何度も呼び出されてしまって具合が悪いので1回呼んだら以降は無視するようにする + // - スクロールイベントは1回のスクロールで複数回発生することがある + // - toleranceの範囲内に収まる程度の微量なスクロールが発生した + let prevTopVisible = firstTopVisible; const onScroll = () => { if (!document.body.contains(el)) return; - if (isTopVisible(el, tolerance)) { - cb(); + + const topVisible = isTopVisible(el, tolerance); + if (topVisible !== prevTopVisible) { + prevTopVisible = topVisible; + cb(topVisible); if (once) removeListener(); } }; @@ -126,6 +134,7 @@ export function scrollToBottom( export function isTopVisible(el: HTMLElement, tolerance = 1): boolean { const scrollTop = getScrollPosition(el); + if (_DEV_) console.log(scrollTop, tolerance, scrollTop <= tolerance); return scrollTop <= tolerance; } diff --git a/packages/frontend/src/components/MkPagination.vue b/packages/frontend/src/components/MkPagination.vue index d30f915c55..ea299c319e 100644 --- a/packages/frontend/src/components/MkPagination.vue +++ b/packages/frontend/src/components/MkPagination.vue @@ -125,8 +125,6 @@ const items = ref(new Map()); */ const queue = ref(new Map()); -const offset = ref(0); - /** * 初期化中かどうか(trueならMkLoadingで全て隠す) */ @@ -179,7 +177,9 @@ watch([backed, contentEl], () => { if (!backed.value) { if (!contentEl.value) return; - scrollRemove.value = (props.pagination.reversed ? onScrollBottom : onScrollTop)(contentEl.value, executeQueue, TOLERANCE); + scrollRemove.value = props.pagination.reversed + ? onScrollBottom(contentEl.value, executeQueue, TOLERANCE) + : onScrollTop(contentEl.value, (topVisible) => { if (topVisible) executeQueue(); }, TOLERANCE); } else { if (scrollRemove.value) scrollRemove.value(); scrollRemove.value = null; @@ -223,7 +223,6 @@ async function init(): Promise { more.value = true; } - offset.value = res.length; error.value = false; fetching.value = false; }, err => { @@ -244,7 +243,7 @@ const fetchMore = async (): Promise => { ...params, limit: SECOND_FETCH_LIMIT, ...(props.pagination.offsetMode ? { - offset: offset.value, + offset: items.value.size, } : { untilId: Array.from(items.value.keys()).at(-1), }), @@ -294,7 +293,6 @@ const fetchMore = async (): Promise => { moreFetching.value = false; } } - offset.value += res.length; }, err => { moreFetching.value = false; }); @@ -308,7 +306,7 @@ const fetchMoreAhead = async (): Promise => { ...params, limit: SECOND_FETCH_LIMIT, ...(props.pagination.offsetMode ? { - offset: offset.value, + offset: items.value.size, } : { sinceId: Array.from(items.value.keys()).at(-1), }), @@ -320,7 +318,6 @@ const fetchMoreAhead = async (): Promise => { items.value = concatMapWithArray(items.value, res); more.value = true; } - offset.value += res.length; moreFetching.value = false; }, err => { moreFetching.value = false;