Skip to content

Commit 789f4cd

Browse files
committed
fix: 初回ロード時にスクロール位置が末尾から少し上にズレる不具合を修正
1 parent d057645 commit 789f4cd

1 file changed

Lines changed: 29 additions & 14 deletions

File tree

src/components/Main/MainView/MessagesScroller/composables/useMessageScroller.ts

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,26 @@
1-
import type { Ref } from 'vue'
1+
import type { Reactive, Ref } from 'vue'
22
import { reactive, watch } from 'vue'
33

44
import type { ChangeHeightData } from '/@/components/Main/MainView/MessageElement/composables/useElementRenderObserver'
55
import type { LoadingDirection } from '/@/components/Main/MainView/MessagesScroller/composables/useMessagesFetcher'
6+
import { defer } from '/@/lib/basic/timer'
67
import type { MessageId } from '/@/types/entity-ids'
78

89
const useMessageScroller = (
910
rootRef: Ref<HTMLElement | null>,
10-
scrollerProps: {
11+
scrollerProps: Reactive<{
1112
messageIds: MessageId[]
1213
lastLoadingDirection: LoadingDirection
1314
entryMessageId?: MessageId
14-
}
15+
}>
1516
) => {
1617
const state = reactive({
1718
height: 0,
1819
scrollTop: 0
1920
})
2021

21-
const onChangeHeight = (payload: ChangeHeightData) => {
22-
if (!rootRef.value) {
23-
return
24-
}
22+
const onChangeHeight = async (payload: ChangeHeightData) => {
23+
if (!rootRef.value) return
2524

2625
if (
2726
scrollerProps.lastLoadingDirection === 'around' &&
@@ -49,20 +48,34 @@ const useMessageScroller = (
4948
scrollerProps.lastLoadingDirection === 'former'
5049
) {
5150
const scrollerTop = rootRef.value.getBoundingClientRect().top
51+
5252
// 視界より上にある要素の高さが変わった場合のみ補正する
53-
if (payload.top < scrollerTop) {
54-
rootRef.value.scrollTo({
55-
top: rootRef.value.scrollTop + payload.heightDiff
56-
})
53+
if (
54+
(payload.heightDiff > 0 && payload.bottom < scrollerTop) ||
55+
(payload.heightDiff < 0 && payload.top < scrollerTop)
56+
) {
57+
rootRef.value.scrollBy({ top: payload.heightDiff })
5758
}
59+
60+
const scrollBottom = rootRef.value.scrollTop + rootRef.value.clientHeight
61+
62+
// 末尾付近を閲覧しているときは,末尾を保つ
63+
if (state.height - scrollBottom <= 50) {
64+
if (!rootRef.value) return
65+
66+
// 複数の onChangeHeight が同フレーム内に複数回呼ばれる場合があるので,
67+
// すべての更新を待ってからスクロールする
68+
await defer()
69+
rootRef.value.scrollTo({ top: rootRef.value.scrollHeight })
70+
}
71+
5872
state.height = rootRef.value.scrollHeight
5973
}
6074
}
6175

6276
const onEntryMessageLoaded = (relativePos: number) => {
63-
if (!rootRef.value) {
64-
return
65-
}
77+
if (!rootRef.value) return
78+
6679
const rootHeight = rootRef.value.getBoundingClientRect().height
6780
rootRef.value.scrollTo({ top: relativePos - rootHeight / 3 })
6881
}
@@ -94,6 +107,7 @@ const useMessageScroller = (
94107
rootRef.value.scrollTo({ top: newHeight })
95108
}
96109
state.height = newHeight
110+
97111
return
98112
}
99113
//上に追加された時はスクロール位置を変更する。
@@ -109,6 +123,7 @@ const useMessageScroller = (
109123
rootRef.value.scrollTo({
110124
top: newHeight
111125
})
126+
112127
state.height = newHeight
113128
}
114129
} else state.height = newHeight

0 commit comments

Comments
 (0)