diff --git a/packages/cdk/scroll/__tests__/__snapshots__/virtualScroll.spec.ts.snap b/packages/cdk/scroll/__tests__/__snapshots__/virtualScroll.spec.ts.snap index 38e2f009e..f64db1999 100644 --- a/packages/cdk/scroll/__tests__/__snapshots__/virtualScroll.spec.ts.snap +++ b/packages/cdk/scroll/__tests__/__snapshots__/virtualScroll.spec.ts.snap @@ -1,8 +1,8 @@ // Vitest Snapshot v1 exports[`VirtualScroll > basic work > render work 1`] = ` -"
-
+"
+
key-0 - 0key-1 - 1key-2 - 2key-3 - 3key-4 - 4key-5 - 5key-6 - 6key-7 - 7key-8 - 8key-9 - 9key-10 - 10
@@ -13,8 +13,8 @@ exports[`VirtualScroll > basic work > render work 1`] = ` `; exports[`VirtualScroll > basic work > rowRender work 1`] = ` -"
-
+"
+
key-0 - 0key-1 - 1key-2 - 2key-3 - 3key-4 - 4key-5 - 5key-6 - 6key-7 - 7key-8 - 8key-9 - 9key-10 - 10
diff --git a/packages/cdk/scroll/__tests__/virtualScroll.spec.ts b/packages/cdk/scroll/__tests__/virtualScroll.spec.ts index 0a147d9a4..5018b1a50 100644 --- a/packages/cdk/scroll/__tests__/virtualScroll.spec.ts +++ b/packages/cdk/scroll/__tests__/virtualScroll.spec.ts @@ -2,7 +2,7 @@ import { MountingOptions, VueWrapper, flushPromises, mount } from '@vue/test-uti import { h } from 'vue' import VirtualScroll from '../src/virtual/VirtualScroll' -import { VirtualRowRenderFn, VirtualScrollInstance, VirtualScrollProps } from '../src/virtual/types' +import { VirtualColRenderFn, VirtualRowRenderFn, VirtualScrollInstance, VirtualScrollProps } from '../src/virtual/types' const getData = (length: number, key = 'key') => { const data: { key: string }[] = [] @@ -11,14 +11,29 @@ const getData = (length: number, key = 'key') => { } return data } +const getGridData = ( + rowLength: number, + colLength: number, + rowKey = 'row', + colKey = 'col', +): { key: string; data: { key: string }[] }[] => { + const data = Array.from(new Array(rowLength)).map((_, rowIndex) => ({ + key: `${rowKey}-${rowIndex}`, + data: Array.from(new Array(colLength)).map((_, colIndex) => ({ key: `${colKey}-${colIndex}` })), + })) + + return data +} const defaultProps = { height: 200, + width: 200, rowHeight: 20, + colWidth: 20, getKey: 'key', } as const -const defaultItemSlot = ` +const defaultRowSlot = ` @@ -27,28 +42,37 @@ const defaultItemSlot = ` describe('VirtualScroll', () => { const VirtualScrollMount = (options?: MountingOptions>) => { const { props, ...rest } = options || {} - const mergedOptions = { props: { ...defaultProps, ...props }, ...rest } as MountingOptions - const scrollHeight = (props?.dataSource?.length ?? 0) * 20 - - vi.spyOn(HTMLElement.prototype, 'scrollHeight', 'get').mockImplementation(() => scrollHeight) - - return mount(VirtualScroll, mergedOptions) as VueWrapper + const mergedOptions = { + props: { ...defaultProps, ...props }, + ...rest, + } as MountingOptions + const rowLength = props?.dataSource?.length + const scrollHeight = rowLength ? rowLength * 20 : 200 + let colLength = 0 + + const row = props?.dataSource?.[0] as { data: unknown[] } | undefined + + if (row?.data) { + colLength = row.data.length + } + const scrollWidth = colLength ? colLength * 20 : 200 + + const wrapper = mount(VirtualScroll, mergedOptions) as VueWrapper + const holderEl = wrapper.vm.getHolderElement() + + vi.spyOn(holderEl, 'scrollHeight', 'get').mockImplementation(() => scrollHeight) + vi.spyOn(holderEl, 'scrollWidth', 'get').mockImplementation(() => scrollWidth) + vi.spyOn(holderEl, 'clientHeight', 'get').mockImplementation(() => 200) + vi.spyOn(holderEl, 'clientWidth', 'get').mockImplementation(() => 200) + + return wrapper } - beforeAll(() => { - vi.spyOn(HTMLElement.prototype, 'clientHeight', 'get').mockImplementation(() => 200) - }) - - afterEach(() => { - vi.spyOn(HTMLElement.prototype, 'clientHeight', 'get').mockClear() - vi.spyOn(HTMLElement.prototype, 'scrollHeight', 'get').mockClear() - }) - describe('basic work', () => { test('render work', async () => { const wrapper = VirtualScrollMount({ props: { dataSource: getData(20) }, - slots: { item: defaultItemSlot }, + slots: { row: defaultRowSlot }, }) expect(wrapper.html()).toMatchSnapshot() @@ -62,7 +86,7 @@ describe('VirtualScroll', () => { test.skip('tag work', async () => { const wrapper = VirtualScrollMount({ props: { dataSource: getData(20) }, - slots: { item: defaultItemSlot }, + slots: { item: defaultRowSlot }, }) expect(wrapper.find('.cdk-virtual-scroll-holder').element.tagName).toEqual('DIV') @@ -80,7 +104,7 @@ describe('VirtualScroll', () => { test('dataSource work', async () => { const wrapper = VirtualScrollMount({ props: { dataSource: getData(5) }, - slots: { item: defaultItemSlot }, + slots: { item: defaultRowSlot }, }) expect(wrapper.findAll('.virtual-item').length).toEqual(5) @@ -97,7 +121,7 @@ describe('VirtualScroll', () => { test('fullHeight work', async () => { const wrapper = VirtualScrollMount({ props: { dataSource: getData(5) }, - slots: { item: defaultItemSlot }, + slots: { item: defaultRowSlot }, }) expect(wrapper.find('.cdk-virtual-scroll-holder').attributes('style')).toContain('height: 200px') @@ -114,7 +138,7 @@ describe('VirtualScroll', () => { test('height work', async () => { const wrapper = VirtualScrollMount({ props: { dataSource: getData(5) }, - slots: { item: defaultItemSlot }, + slots: { item: defaultRowSlot }, }) expect(wrapper.find('.cdk-virtual-scroll-holder').attributes('style')).toContain('height: 200px') @@ -134,7 +158,7 @@ describe('VirtualScroll', () => { test('itemHeight work', async () => { const wrapper = VirtualScrollMount({ props: { dataSource: getData(5) }, - slots: { item: defaultItemSlot }, + slots: { item: defaultRowSlot }, }) expect(wrapper.findAll('.virtual-item').length).toEqual(5) @@ -151,7 +175,7 @@ describe('VirtualScroll', () => { test('getKey work', async () => { const wrapper = VirtualScrollMount({ props: { dataSource: getData(20) }, - slots: { item: defaultItemSlot }, + slots: { item: defaultRowSlot }, }) wrapper.findAll('.virtual-item').forEach((item, index) => expect(item.text()).toEqual(`key-${index} - ${index}`)) @@ -176,48 +200,92 @@ describe('VirtualScroll', () => { describe('scroll work', () => { test('scrollTo work', async () => { + const rowRender: VirtualRowRenderFn = ({ children }) => { + return h('div', { class: 'virtual-row' }, children) + } + const colRender: VirtualColRenderFn = ({ item, index }) => { + const { key } = item as { key: string } + + return h('div', { class: 'virtual-col' }, [`${key}-${index}`]) + } + vi.useFakeTimers() const wrapper = VirtualScrollMount({ - props: { dataSource: getData(40) }, - slots: { item: defaultItemSlot }, + props: { dataSource: getGridData(40, 40), rowRender, colRender }, }) expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollTop).toEqual(0) wrapper.vm.scrollTo(100) vi.runAllTimers() - expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollTop).toEqual(100) - wrapper.vm.scrollTo({ index: 20, align: 'top' }) + wrapper.vm.scrollTo({ rowIndex: 20, verticalAlign: 'top' }) vi.runAllTimers() - expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollTop).toEqual(400) - wrapper.vm.scrollTo({ index: 20, align: 'bottom' }) + wrapper.vm.scrollTo({ rowIndex: 20, verticalAlign: 'bottom' }) vi.runAllTimers() - expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollTop).toEqual(220) - wrapper.vm.scrollTo({ key: 'key-20', align: 'top' }) + wrapper.vm.scrollTo({ rowKey: 'row-20', verticalAlign: 'top' }) vi.runAllTimers() + expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollTop).toEqual(400) + wrapper.vm.scrollTo({ rowKey: 'row-20', verticalAlign: 'top', verticalOffset: 20 }) + vi.runAllTimers() + expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollTop).toEqual(380) + + wrapper.vm.scrollTo({ top: 100, left: 100 }) + vi.runAllTimers() + expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollTop).toEqual(100) + expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollLeft).toEqual(100) + + wrapper.vm.scrollTo({ rowIndex: 20, colIndex: 20, verticalAlign: 'top', horizontalAlign: 'start' }) + vi.runAllTimers() expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollTop).toEqual(400) + expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollLeft).toEqual(400) - wrapper.vm.scrollTo({ key: 'key-20', align: 'top', offset: 20 }) + wrapper.vm.scrollTo({ rowIndex: 20, colIndex: 20, verticalAlign: 'bottom', horizontalAlign: 'end' }) vi.runAllTimers() + expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollTop).toEqual(220) + expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollLeft).toEqual(220) + wrapper.vm.scrollTo({ rowKey: 'row-20', colKey: 'col-20', verticalAlign: 'top', horizontalAlign: 'start' }) + vi.runAllTimers() + expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollTop).toEqual(400) + expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollLeft).toEqual(400) + + wrapper.vm.scrollTo({ + rowKey: 'row-20', + colKey: 'col-20', + verticalAlign: 'top', + horizontalAlign: 'start', + verticalOffset: 20, + horizontalOffset: 20, + }) + vi.runAllTimers() expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollTop).toEqual(380) + expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollLeft).toEqual(380) wrapper.vm.scrollTo(9999) vi.runAllTimers() + expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollTop).toEqual(600) + wrapper.vm.scrollTo({ top: 9999, left: 9999 }) + vi.runAllTimers() expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollTop).toEqual(600) + expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollLeft).toEqual(600) wrapper.vm.scrollTo(-1) vi.runAllTimers() + expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollTop).toEqual(0) + wrapper.vm.scrollTo({ top: -1, left: -1 }) + vi.runAllTimers() expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollTop).toEqual(0) + expect(wrapper.find('.cdk-virtual-scroll-holder').element.scrollLeft).toEqual(0) + vi.useRealTimers() }) @@ -225,7 +293,7 @@ describe('VirtualScroll', () => { const onScroll = vi.fn() const wrapper = VirtualScrollMount({ props: { dataSource: getData(100) }, - slots: { item: defaultItemSlot }, + slots: { item: defaultRowSlot }, attrs: { onScroll }, }) @@ -239,7 +307,7 @@ describe('VirtualScroll', () => { test('moving work', async () => { const wrapper = VirtualScrollMount({ props: { dataSource: getData(100) }, - slots: { item: defaultItemSlot }, + slots: { item: defaultRowSlot }, }) wrapper.find('.cdk-virtual-scroll-holder').trigger('touchstart', { touches: [{ pageY: 100 }] }) diff --git a/packages/cdk/scroll/demo/Basic.vue b/packages/cdk/scroll/demo/Basic.vue index ebbdee78d..164d590f4 100644 --- a/packages/cdk/scroll/demo/Basic.vue +++ b/packages/cdk/scroll/demo/Basic.vue @@ -19,11 +19,13 @@ Scroll To 100px - Scroll To key-50(top) + Scroll To key-50(top) Scroll To 40(top) - Scroll To 40(bottom) - Scroll To 40(auto) - Scroll To 40(top) + 15 offset + Scroll To 40(bottom) + Scroll To 40(auto) + + Scroll To 40(top) + 15 offset +
diff --git a/packages/cdk/scroll/demo/Both.vue b/packages/cdk/scroll/demo/Both.vue index 6401be15d..af7aa18de 100644 --- a/packages/cdk/scroll/demo/Both.vue +++ b/packages/cdk/scroll/demo/Both.vue @@ -14,13 +14,49 @@ {{ row.key }} - {{ index }} + + Scroll To [100px, 100px] + + Scroll To [row-key-50, col-key-50](top, end) + + + Scroll To [40, 40](top, start) + + + Scroll To [40, 40](bottom, end) + + + Scroll To [40, 40](auto) + + + Scroll To [100, 100](top, start) + 15 offset + +