From 25f6e30f17953bf6f4d5f6fe421aef1d5574b4bf Mon Sep 17 00:00:00 2001 From: Nikola Begedin Date: Wed, 4 Jan 2023 20:15:23 +0100 Subject: [PATCH] fix(useVirtualList): List sometimes missing elements (#2477) * FIX 2065: List sometimes missing elements Add tests * Fix import * Undo change + fix tests * Contrain PR to only the single bugfix * Undo formatting change * Undo formatting change Co-authored-by: wheat --- packages/core/useVirtualList/index.test.ts | 114 +++++++++++++++++++++ packages/core/useVirtualList/index.ts | 13 ++- 2 files changed, 120 insertions(+), 7 deletions(-) create mode 100644 packages/core/useVirtualList/index.test.ts diff --git a/packages/core/useVirtualList/index.test.ts b/packages/core/useVirtualList/index.test.ts new file mode 100644 index 00000000000..17b514d5736 --- /dev/null +++ b/packages/core/useVirtualList/index.test.ts @@ -0,0 +1,114 @@ +import { ref } from 'vue-demi' +import { useVirtualList } from '.' + +describe('useVirtualList', () => { + it('should be defined', () => { + expect(useVirtualList).toBeDefined() + }) +}) + +describe('useVirtualList, vertical', () => { + it('returns all original items if they fit the container', () => { + const { + list, + containerProps: { ref: containerRef }, + scrollTo, + } = useVirtualList(ref(['a', 'b', 'c', 'd', 'e', 'f']), { itemHeight: () => 50, overscan: 1 }) + const div = { ...document.createElement('div'), clientHeight: 50 } + + containerRef.value = div + + containerRef.value = { ...div, clientHeight: 200 } + scrollTo(0) + expect(list.value.map(i => i.data)).toEqual(['a', 'b', 'c', 'd', 'e', 'f']) + + containerRef.value = { ...div, clientHeight: 250 } + scrollTo(0) + expect(list.value.map(i => i.data)).toEqual(['a', 'b', 'c', 'd', 'e', 'f']) + }) + + it('returns the current visible window of items if there are too many for the container', () => { + const { + list, + containerProps: { ref: containerRef }, + scrollTo, + } = useVirtualList(ref(['a', 'b', 'c', 'd', 'e', 'f', 'g']), { itemHeight: () => 50, overscan: 1 }) + const div = { ...document.createElement('div'), clientHeight: 50 } + + containerRef.value = div + + scrollTo(0) + expect(list.value.map(i => i.data)).toEqual(['a', 'b', 'c']) + + scrollTo(1) + expect(list.value.map(i => i.data)).toEqual(['a', 'b', 'c']) + + scrollTo(2) + expect(list.value.map(i => i.data)).toEqual(['b', 'c', 'd']) + + scrollTo(3) + expect(list.value.map(i => i.data)).toEqual(['c', 'd', 'e']) + + scrollTo(4) + expect(list.value.map(i => i.data)).toEqual(['d', 'e', 'f']) + + scrollTo(5) + expect(list.value.map(i => i.data)).toEqual(['e', 'f', 'g']) + + scrollTo(6) + expect(list.value.map(i => i.data)).toEqual(['f', 'g']) + }) +}) + +describe('useVirtualList, horizontal', () => { + it('returns all original items if they fit the container', () => { + const { + list, + containerProps: { ref: containerRef }, + scrollTo, + } = useVirtualList(ref(['a', 'b', 'c', 'd', 'e', 'f']), { itemWidth: () => 50, overscan: 1 }) + const div = { ...document.createElement('div'), clientWidth: 50 } + + containerRef.value = div + + containerRef.value = { ...div, clientWidth: 200 } + scrollTo(0) + expect(list.value.map(i => i.data)).toEqual(['a', 'b', 'c', 'd', 'e', 'f']) + + containerRef.value = { ...div, clientWidth: 250 } + scrollTo(0) + expect(list.value.map(i => i.data)).toEqual(['a', 'b', 'c', 'd', 'e', 'f']) + }) + + it('returns the current visible window of items if there are too many for the container', () => { + const { + list, + containerProps: { ref: containerRef }, + scrollTo, + } = useVirtualList(ref(['a', 'b', 'c', 'd', 'e', 'f', 'g']), { itemWidth: () => 50, overscan: 1 }) + const div = { ...document.createElement('div'), clientWidth: 50 } + + containerRef.value = div + + scrollTo(0) + expect(list.value.map(i => i.data)).toEqual(['a', 'b', 'c']) + + scrollTo(1) + expect(list.value.map(i => i.data)).toEqual(['a', 'b', 'c']) + + scrollTo(2) + expect(list.value.map(i => i.data)).toEqual(['b', 'c', 'd']) + + scrollTo(3) + expect(list.value.map(i => i.data)).toEqual(['c', 'd', 'e']) + + scrollTo(4) + expect(list.value.map(i => i.data)).toEqual(['d', 'e', 'f']) + + scrollTo(5) + expect(list.value.map(i => i.data)).toEqual(['e', 'f', 'g']) + + scrollTo(6) + expect(list.value.map(i => i.data)).toEqual(['f', 'g']) + }) +}) diff --git a/packages/core/useVirtualList/index.ts b/packages/core/useVirtualList/index.ts index 42b3e22c1be..c0656b83d87 100644 --- a/packages/core/useVirtualList/index.ts +++ b/packages/core/useVirtualList/index.ts @@ -120,20 +120,19 @@ function useVirtualListResources(list: MaybeRef): UseVirtualListResource } function createGetViewCapacity(state: UseVirtualListResources['state'], source: UseVirtualListResources['source'], itemSize: UseVirtualListItemSize) { - return (containerHeight: number) => { + return (containerSize: number) => { if (typeof itemSize === 'number') - return Math.ceil(containerHeight / itemSize) + return Math.ceil(containerSize / itemSize) const { start = 0 } = state.value let sum = 0 let capacity = 0 for (let i = start; i < source.value.length; i++) { - const height = itemSize(i) - sum += height - if (sum >= containerHeight) { - capacity = i + const size = itemSize(i) + sum += size + capacity = i + if (sum > containerSize) break - } } return capacity - start }