1- import { ref , reactive , readonly , onUnmounted , nextTick , type Ref } from 'vue'
1+ import { ref , reactive , readonly , onBeforeUnmount , nextTick , type Ref } from 'vue'
22import { useDebounceFn } from '@vueuse/core'
33import type { ScrollInfo } from './types'
44import type { DynamicScroller } from 'vue-virtual-scroller'
@@ -30,6 +30,8 @@ export function useMessageScroll(options?: UseMessageScrollOptions) {
3030 let intersectionObserver : IntersectionObserver | null = null
3131 let scrollRetryTimer : number | null = null
3232 let scrollRetryToken = 0
33+ let bottomScrollRetryTimer : number | null = null
34+ let bottomScrollCancelToken = 0
3335 let pendingScrollTargetId : string | null = null
3436
3537 const updateScrollInfoImmediate = ( ) => {
@@ -63,6 +65,12 @@ export function useMessageScroll(options?: UseMessageScrollOptions) {
6365 * Schedule scroll to bottom with retry mechanism for virtual scroller
6466 */
6567 const scheduleScrollToBottom = ( force = false ) => {
68+ if ( bottomScrollRetryTimer ) {
69+ clearTimeout ( bottomScrollRetryTimer )
70+ bottomScrollRetryTimer = null
71+ }
72+ const currentBottomToken = ++ bottomScrollCancelToken
73+
6674 nextTick ( ( ) => {
6775 const shouldAutoFollow = options ?. shouldAutoFollow
6876 if ( force && shouldAutoFollow ) {
@@ -83,10 +91,14 @@ export function useMessageScroll(options?: UseMessageScrollOptions) {
8391 let lastScrollHeight = 0
8492
8593 const attemptScrollToBottom = ( ) => {
94+ if ( currentBottomToken !== bottomScrollCancelToken ) return
8695 scroller . scrollToBottom ( )
8796
8897 nextTick ( ( ) => {
89- setTimeout ( ( ) => {
98+ bottomScrollRetryTimer = window . setTimeout ( ( ) => {
99+ bottomScrollRetryTimer = null
100+ if ( currentBottomToken !== bottomScrollCancelToken ) return
101+
90102 const container = messagesContainer . value
91103 if ( ! container ) {
92104 updateScrollInfo ( )
@@ -268,7 +280,7 @@ export function useMessageScroll(options?: UseMessageScrollOptions) {
268280 updateScrollInfoImmediate ( )
269281 }
270282
271- onUnmounted ( ( ) => {
283+ onBeforeUnmount ( ( ) => {
272284 if ( intersectionObserver ) {
273285 intersectionObserver . disconnect ( )
274286 intersectionObserver = null
@@ -279,6 +291,12 @@ export function useMessageScroll(options?: UseMessageScrollOptions) {
279291 scrollRetryTimer = null
280292 }
281293
294+ if ( bottomScrollRetryTimer ) {
295+ clearTimeout ( bottomScrollRetryTimer )
296+ bottomScrollRetryTimer = null
297+ }
298+ bottomScrollCancelToken ++
299+
282300 pendingScrollTargetId = null
283301 } )
284302
0 commit comments