diff --git a/src/table/__tests__/pagination/onpage-scroll.test.jsx b/src/table/__tests__/pagination/onpage-scroll.test.jsx new file mode 100644 index 000000000..831ed12de --- /dev/null +++ b/src/table/__tests__/pagination/onpage-scroll.test.jsx @@ -0,0 +1,129 @@ +import { afterEach } from 'vitest'; +import { mount } from '@vue/test-utils'; +import { + Table, BaseTable, PrimaryTable, EnhancedTable, +} from '@/src/table/index.ts'; + +// 与项目中其它分页测试风格保持一致,针对受控分页(on page-change)和切页时滚动回顶部进行断言 +const TABLES = [Table, BaseTable, PrimaryTable, EnhancedTable]; + +function createData(total) { + return new Array(total).fill(null).map((_, i) => { + let applicant = `Name${i + 1}`; + if (i === 2) applicant = '王芳'; + if (i === 3) applicant = '贾明'; + return { + id: i + 1, + index: i + 1, + applicant, + }; + }); +} + +TABLES.forEach((TTable) => { + describe(`${TTable.name} pagination onPageChange & scroll reset`, () => { + afterEach(() => { + document.querySelector('.t-popup')?.remove(); + document.querySelector('.t-table')?.remove(); + }); + + it('props.pagination: onPageChange should be triggered when switching pages', async () => { + const onPageChange = vi.fn(); + const pagination = { + current: 1, + pageSize: 2, + total: 10, + }; + + const wrapper = mount({ + data() { + return { data: createData(10), pagination }; + }, + render() { + return ( + + ); + }, + }); + + expect(wrapper.find('.t-table__pagination').exists()).toBeTruthy(); + const nextButton = wrapper.find('.t-pagination__btn-next'); + expect(nextButton.exists()).toBeTruthy(); + + await nextButton.trigger('click'); + + expect(onPageChange).toHaveBeenCalledTimes(1); + expect(onPageChange).toHaveBeenCalledWith( + expect.objectContaining({ current: 2, pageSize: 2, previous: 1 }), + expect.arrayContaining([ + expect.objectContaining({ index: 3, applicant: '王芳' }), + expect.objectContaining({ index: 4, applicant: '贾明' }), + ]), + ); + }); + + it('props.pagination: scroll position should reset when switching pages', async () => { + const onPageChange = vi.fn(); + const pagination = { + current: 1, + pageSize: 2, + total: 50, + }; + + const wrapper = mount({ + data() { + return { data: createData(50), pagination }; + }, + render() { + return ( + + ); + }, + }); + + expect(wrapper.find('.t-table__pagination').exists()).toBeTruthy(); + const tableContent = wrapper.find('.t-table__content'); + expect(tableContent.exists()).toBeTruthy(); + + const scrollElement = tableContent.element; + + // JSDOM 下 scrollHeight/clientHeight 默认为 0,需要 mock + Object.defineProperty(scrollElement, 'scrollHeight', { value: 100, configurable: true }); + Object.defineProperty(scrollElement, 'clientHeight', { value: 50, configurable: true }); + + expect(scrollElement.scrollHeight).toBeGreaterThan(scrollElement.clientHeight); + expect(scrollElement.scrollTop).toBe(0); + + // 模拟滚动到底部 + scrollElement.scrollTop = 100; + expect(scrollElement.scrollTop).toBe(100); + + const nextButton = wrapper.find('.t-pagination__btn-next'); + expect(nextButton.exists()).toBeTruthy(); + await nextButton.trigger('click'); + + expect(onPageChange).toHaveBeenCalledTimes(1); + // 切页后滚动回到顶部 + expect(scrollElement.scrollTop).toBe(0); + }); + }); +}); diff --git a/src/table/base-table.tsx b/src/table/base-table.tsx index b1a4c380a..581ee9d24 100644 --- a/src/table/base-table.tsx +++ b/src/table/base-table.tsx @@ -128,7 +128,11 @@ export default defineComponent({ const { dataSource, innerPagination, isPaginateData, renderPagination, - } = usePagination(props, context); + } = usePagination( + props, + context, + tableContentRef, + ); const onInnerResizeChange: BaseTableProps['onColumnResizeChange'] = (p) => { props.onColumnResizeChange?.(p); diff --git a/src/table/hooks/usePagination.tsx b/src/table/hooks/usePagination.tsx index 31cda200f..7ba94dbe7 100644 --- a/src/table/hooks/usePagination.tsx +++ b/src/table/hooks/usePagination.tsx @@ -58,7 +58,11 @@ export function usePaginationValue( return [innerPagination, setInnerPagination]; } -export default function usePagination(props: TdBaseTableProps, context: SetupContext) { +export default function usePagination( + props: TdBaseTableProps, + context: SetupContext, + tableContentRef: Ref, +) { const { pagination, disableDataPage, data } = toRefs(props); const { classPrefix } = useConfig(); const dataSource = ref([]); @@ -67,6 +71,15 @@ export default function usePagination(props: TdBaseTableProps, context: SetupCon // Vue3 ignore this line context.emit('page-change', pageInfo, newData); props.onPageChange?.(pageInfo, newData); + + const ref = tableContentRef.value; + if (ref.scrollTo) { + ref.scrollTo({ top: 0, left: 0, behavior: 'smooth' }); + } else { + // 兼容测试环境或旧浏览器 + ref.scrollTop = 0; + ref.scrollLeft = 0; + } }; const [innerPagination, setInnerPagination] = usePaginationValue(pagination, onPageChange);