From 78c8c9d7915ecf1cbfda4d9c9baf7d3180b03d51 Mon Sep 17 00:00:00 2001 From: tangjinzhou <415800467@qq.com> Date: Fri, 21 Apr 2023 11:12:45 +0800 Subject: [PATCH] fix: virtual list error at firefox, close #6470 --- components/vc-virtual-list/List.tsx | 13 +++++++--- components/vc-virtual-list/ScrollBar.tsx | 25 ++++++++++--------- .../vc-virtual-list/hooks/useHeights.tsx | 20 +++++++++------ .../vc-virtual-list/hooks/useScrollTo.tsx | 2 +- 4 files changed, 35 insertions(+), 25 deletions(-) diff --git a/components/vc-virtual-list/List.tsx b/components/vc-virtual-list/List.tsx index f234077ed..5d689d57a 100644 --- a/components/vc-virtual-list/List.tsx +++ b/components/vc-virtual-list/List.tsx @@ -226,8 +226,13 @@ const List = defineComponent({ offset: undefined, }); } + if (componentRef.value) { + state.scrollTop = componentRef.value.scrollTop; + } + }, + { + immediate: true, }, - { immediate: true }, ); watch( [ @@ -277,11 +282,11 @@ const List = defineComponent({ itemTop = currentItemBottom; } - // Fallback to normal if not match. This code should never reach - /* istanbul ignore next */ + // When scrollTop at the end but data cut to small count will reach this if (startIndex === undefined) { startIndex = 0; startOffset = 0; + endIndex = Math.ceil(height / itemHeight); } if (endIndex === undefined) { endIndex = dataLen - 1; @@ -325,7 +330,7 @@ const List = defineComponent({ // When data size reduce. It may trigger native scroll event back to fit scroll position function onFallbackScroll(e: UIEvent) { const { scrollTop: newScrollTop } = e.currentTarget as Element; - if (Math.abs(newScrollTop - state.scrollTop) >= 1) { + if (newScrollTop !== state.scrollTop) { syncScrollTop(newScrollTop); } diff --git a/components/vc-virtual-list/ScrollBar.tsx b/components/vc-virtual-list/ScrollBar.tsx index a4a436df2..a6e05a4d8 100644 --- a/components/vc-virtual-list/ScrollBar.tsx +++ b/components/vc-virtual-list/ScrollBar.tsx @@ -119,18 +119,19 @@ export default defineComponent({ this.onScrollbarTouchStart, supportsPassive ? ({ passive: false } as EventListenerOptions) : false, ); - this.thumbRef.current.removeEventListener( - 'touchstart', - this.onMouseDown, - supportsPassive ? ({ passive: false } as EventListenerOptions) : false, - ); - this.thumbRef.current.removeEventListener( - 'touchmove', - this.onMouseMove, - supportsPassive ? ({ passive: false } as EventListenerOptions) : false, - ); - this.thumbRef.current.removeEventListener('touchend', this.onMouseUp); - + if (this.thumbRef.current) { + this.thumbRef.current.removeEventListener( + 'touchstart', + this.onMouseDown, + supportsPassive ? ({ passive: false } as EventListenerOptions) : false, + ); + this.thumbRef.current.removeEventListener( + 'touchmove', + this.onMouseMove, + supportsPassive ? ({ passive: false } as EventListenerOptions) : false, + ); + this.thumbRef.current.removeEventListener('touchend', this.onMouseUp); + } raf.cancel(this.moveRaf); }, diff --git a/components/vc-virtual-list/hooks/useHeights.tsx b/components/vc-virtual-list/hooks/useHeights.tsx index 8cf6e69eb..6057d1904 100644 --- a/components/vc-virtual-list/hooks/useHeights.tsx +++ b/components/vc-virtual-list/hooks/useHeights.tsx @@ -1,6 +1,7 @@ import type { VNodeProps, Ref, ShallowRef } from 'vue'; -import { watch, ref } from 'vue'; +import { onUnmounted, watch, ref } from 'vue'; import type { GetKey } from '../interface'; +import wrapperRaf from '../../_util/raf'; export type CacheMap = Map; @@ -16,14 +17,14 @@ export default function useHeights( watch(mergedData, () => { updatedMark.value = Symbol('update'); }); - let heightUpdateId = 0; + let collectRaf: number = undefined; + + function cancelRaf() { + wrapperRaf.cancel(collectRaf); + } function collectHeight() { - heightUpdateId += 1; - const currentId = heightUpdateId; - Promise.resolve().then(() => { - // Only collect when it's latest call - if (currentId !== heightUpdateId) return; - // let changed = false; + cancelRaf(); + collectRaf = wrapperRaf(() => { instance.forEach((element, key) => { if (element && element.offsetParent) { const { offsetHeight } = element; @@ -57,6 +58,9 @@ export default function useHeights( } } } + onUnmounted(() => { + cancelRaf(); + }); return [setInstance, collectHeight, heights, updatedMark]; } diff --git a/components/vc-virtual-list/hooks/useScrollTo.tsx b/components/vc-virtual-list/hooks/useScrollTo.tsx index c61d32fe1..82a370542 100644 --- a/components/vc-virtual-list/hooks/useScrollTo.tsx +++ b/components/vc-virtual-list/hooks/useScrollTo.tsx @@ -103,7 +103,7 @@ export default function useScrollTo( collectHeight(); } syncScroll(times - 1, newTargetAlign); - }); + }, 2); }; syncScroll(5);