From 3fe7b202a01cf6b2703e122ffabe1a6039dcb0f9 Mon Sep 17 00:00:00 2001 From: RSS1102 Date: Tue, 18 Nov 2025 11:02:34 +0800 Subject: [PATCH 1/7] fix(table): pagination `onPageChange` triggered by `current` prop in controlled mode --- packages/components/table/hooks/usePagination.tsx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/components/table/hooks/usePagination.tsx b/packages/components/table/hooks/usePagination.tsx index b7338aa3a1..0c9499a096 100644 --- a/packages/components/table/hooks/usePagination.tsx +++ b/packages/components/table/hooks/usePagination.tsx @@ -36,11 +36,22 @@ export default function usePagination( () => { if (!pagination.value || !pagination.value.current) return; const { current, pageSize } = pagination.value; - innerPagination.value = { current, pageSize }; + // 保存变化前的 innerPagination,用于判断此次变化是否来自内部 Pagination 的 onChange + const prevInner = { current: innerPagination.value?.current, pageSize: innerPagination.value?.pageSize }; + + const newPageInfo = { current, pageSize }; + innerPagination.value = newPageInfo; updateDataSourceAndPaginate( pagination.value.current, pagination.value.pageSize || pagination.value.defaultPageSize, ); + + if ( + props.onPageChange && + (prevInner.current !== newPageInfo.current || prevInner.pageSize !== newPageInfo.pageSize) + ) { + props.onPageChange?.(newPageInfo as PageInfo, dataSource.value); + } }, { immediate: true }, ); From 3fdb46c7a641e5b27ce6c62a20d439b40e945efc Mon Sep 17 00:00:00 2001 From: RSS1102 Date: Wed, 19 Nov 2025 15:41:27 +0800 Subject: [PATCH 2/7] fix(pagination): update pageInfo handling and trigger onChange callback on current change --- packages/components/pagination/pagination.tsx | 31 ++++++++++--------- .../components/table/__tests__/table.test.tsx | 11 ++++--- .../components/table/hooks/usePagination.tsx | 9 ------ 3 files changed, 22 insertions(+), 29 deletions(-) diff --git a/packages/components/pagination/pagination.tsx b/packages/components/pagination/pagination.tsx index d43c01f03a..c849047ebd 100755 --- a/packages/components/pagination/pagination.tsx +++ b/packages/components/pagination/pagination.tsx @@ -35,8 +35,6 @@ export default defineComponent({ props, setup(props: TdPaginationProps) { - const { emit } = getCurrentInstance(); - const { modelValue, pageSize, current } = toRefs(props); const renderTNodeJSX = useTNodeJSX(); const [innerCurrent, setInnerCurrent] = useVModel( @@ -140,9 +138,18 @@ export default defineComponent({ return array; }); + const pageInfoValue = ref({ + current: innerCurrent.value, + previous: 0, + pageSize: innerPageSize.value, + }); + watch( () => innerCurrent.value, - (val) => (jumpIndex.value = val), + (val) => { + jumpIndex.value = val; + props.onChange?.(pageInfoValue.value); + }, ); const toPage: (pageIndex: number, pageInfo?: PageInfo) => void = (pageIndex, pageInfo) => { @@ -155,6 +162,7 @@ export default defineComponent({ } else if (pageIndex > pageCount.value) { current = pageCount.value; } + if (innerCurrent.value !== current) { const prev = innerCurrent.value; pageInfo = pageInfo || { @@ -162,13 +170,9 @@ export default defineComponent({ previous: prev, pageSize: innerPageSize.value, }; - if (pageInfo) { - setInnerCurrent(current, pageInfo); - props.onChange?.(pageInfo); - } else { - // 非主动更改时应仅更新modelValue不触发onCurrentChange事件 - emit('update:modelValue', current); - } + + setInnerCurrent(current, pageInfo); + pageInfoValue.value = pageInfo; } }; @@ -209,6 +213,7 @@ export default defineComponent({ previous: initialPageInfo.current, pageSize, }; + pageInfoValue.value = pageInfo; toPage(pageCurrent, pageInfo); } else { const pageInfo = { @@ -216,11 +221,7 @@ export default defineComponent({ previous: initialPageInfo.current, pageSize, }; - // 如果在 setInnerPageSize 后 current 被外部受控修改,则触发 currentChange 事件 - if (innerCurrent.value !== pageInfo.previous) { - emit('currentChange', innerCurrent.value, pageInfo); - } - props.onChange?.(pageInfo); + pageInfoValue.value = pageInfo; } }); }; diff --git a/packages/components/table/__tests__/table.test.tsx b/packages/components/table/__tests__/table.test.tsx index 7d921a4e45..6a649c1a1c 100644 --- a/packages/components/table/__tests__/table.test.tsx +++ b/packages/components/table/__tests__/table.test.tsx @@ -349,9 +349,10 @@ describe('BaseTable Component', () => { it('props.pagination: onPageChange should be triggered when switching pages', async () => { const onPageChange = vi.fn(); + const pagination = { - current: 1, - pageSize: 2, + defaultCurrent: 1, + defaultPageSize: 2, total: 10, }; @@ -395,9 +396,10 @@ describe('BaseTable Component', () => { it('props.pagination: scroll position should reset when switching pages', async () => { const onPageChange = vi.fn(); + // 使用非受控模式 const pagination = { - current: 1, - pageSize: 2, + defaultCurrent: 1, + defaultPageSize: 2, total: 50, }; @@ -425,7 +427,6 @@ describe('BaseTable Component', () => { 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/packages/components/table/hooks/usePagination.tsx b/packages/components/table/hooks/usePagination.tsx index 0c9499a096..ad880dfc83 100644 --- a/packages/components/table/hooks/usePagination.tsx +++ b/packages/components/table/hooks/usePagination.tsx @@ -36,8 +36,6 @@ export default function usePagination( () => { if (!pagination.value || !pagination.value.current) return; const { current, pageSize } = pagination.value; - // 保存变化前的 innerPagination,用于判断此次变化是否来自内部 Pagination 的 onChange - const prevInner = { current: innerPagination.value?.current, pageSize: innerPagination.value?.pageSize }; const newPageInfo = { current, pageSize }; innerPagination.value = newPageInfo; @@ -45,13 +43,6 @@ export default function usePagination( pagination.value.current, pagination.value.pageSize || pagination.value.defaultPageSize, ); - - if ( - props.onPageChange && - (prevInner.current !== newPageInfo.current || prevInner.pageSize !== newPageInfo.pageSize) - ) { - props.onPageChange?.(newPageInfo as PageInfo, dataSource.value); - } }, { immediate: true }, ); From 78a3c2306bcfc1b752cc3a7bd5dc4a6c6c151d80 Mon Sep 17 00:00:00 2001 From: RSS1102 Date: Wed, 19 Nov 2025 15:49:38 +0800 Subject: [PATCH 3/7] fix(pagination): remove unused import `getCurrentInstance` from pagination component --- packages/components/pagination/pagination.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/pagination/pagination.tsx b/packages/components/pagination/pagination.tsx index c849047ebd..a557897af8 100755 --- a/packages/components/pagination/pagination.tsx +++ b/packages/components/pagination/pagination.tsx @@ -1,4 +1,4 @@ -import { defineComponent, computed, ref, watch, toRefs, getCurrentInstance, nextTick } from 'vue'; +import { defineComponent, computed, ref, watch, toRefs, nextTick } from 'vue'; import { isNaN, isObject } from 'lodash-es'; import { PageFirstIcon as TdPageFirstIcon, From 4e329ca936b2190b6c8d1723c2c668d574bf4c6f Mon Sep 17 00:00:00 2001 From: RSS1102 Date: Wed, 19 Nov 2025 16:19:19 +0800 Subject: [PATCH 4/7] fix(pagination): remove unused pageInfoValue and trigger onChange with pageInfo directly --- packages/components/pagination/pagination.tsx | 16 +++++++--------- .../components/table/__tests__/table.test.tsx | 11 +++++------ 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/packages/components/pagination/pagination.tsx b/packages/components/pagination/pagination.tsx index a557897af8..d9cfa45896 100755 --- a/packages/components/pagination/pagination.tsx +++ b/packages/components/pagination/pagination.tsx @@ -138,17 +138,16 @@ export default defineComponent({ return array; }); - const pageInfoValue = ref({ - current: innerCurrent.value, - previous: 0, - pageSize: innerPageSize.value, - }); + // const pageInfoValue = ref({ + // current: innerCurrent.value, + // previous: 0, + // pageSize: innerPageSize.value, + // }); watch( () => innerCurrent.value, (val) => { jumpIndex.value = val; - props.onChange?.(pageInfoValue.value); }, ); @@ -172,7 +171,7 @@ export default defineComponent({ }; setInnerCurrent(current, pageInfo); - pageInfoValue.value = pageInfo; + props.onChange?.(pageInfo); } }; @@ -213,7 +212,6 @@ export default defineComponent({ previous: initialPageInfo.current, pageSize, }; - pageInfoValue.value = pageInfo; toPage(pageCurrent, pageInfo); } else { const pageInfo = { @@ -221,7 +219,7 @@ export default defineComponent({ previous: initialPageInfo.current, pageSize, }; - pageInfoValue.value = pageInfo; + props.onChange?.(pageInfo); } }); }; diff --git a/packages/components/table/__tests__/table.test.tsx b/packages/components/table/__tests__/table.test.tsx index 6a649c1a1c..7d921a4e45 100644 --- a/packages/components/table/__tests__/table.test.tsx +++ b/packages/components/table/__tests__/table.test.tsx @@ -349,10 +349,9 @@ describe('BaseTable Component', () => { it('props.pagination: onPageChange should be triggered when switching pages', async () => { const onPageChange = vi.fn(); - const pagination = { - defaultCurrent: 1, - defaultPageSize: 2, + current: 1, + pageSize: 2, total: 10, }; @@ -396,10 +395,9 @@ describe('BaseTable Component', () => { it('props.pagination: scroll position should reset when switching pages', async () => { const onPageChange = vi.fn(); - // 使用非受控模式 const pagination = { - defaultCurrent: 1, - defaultPageSize: 2, + current: 1, + pageSize: 2, total: 50, }; @@ -427,6 +425,7 @@ describe('BaseTable Component', () => { 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); From 582836aa3276db5a792eb81cfa88ba394913ac5b Mon Sep 17 00:00:00 2001 From: RSS1102 Date: Wed, 19 Nov 2025 17:17:47 +0800 Subject: [PATCH 5/7] fix(pagination): refactor pageInfo handling and simplify current page updates --- packages/components/pagination/pagination.tsx | 77 ++++++++----------- 1 file changed, 33 insertions(+), 44 deletions(-) diff --git a/packages/components/pagination/pagination.tsx b/packages/components/pagination/pagination.tsx index d9cfa45896..5b6d72b791 100755 --- a/packages/components/pagination/pagination.tsx +++ b/packages/components/pagination/pagination.tsx @@ -138,12 +138,6 @@ export default defineComponent({ return array; }); - // const pageInfoValue = ref({ - // current: innerCurrent.value, - // previous: 0, - // pageSize: innerPageSize.value, - // }); - watch( () => innerCurrent.value, (val) => { @@ -155,24 +149,22 @@ export default defineComponent({ if (props.disabled) { return; } - let current = pageIndex; + + let toPageCurrent = pageIndex; if (pageIndex < min) { - current = min; + toPageCurrent = min; } else if (pageIndex > pageCount.value) { - current = pageCount.value; + toPageCurrent = pageCount.value; } - if (innerCurrent.value !== current) { - const prev = innerCurrent.value; - pageInfo = pageInfo || { - current, - previous: prev, - pageSize: innerPageSize.value, - }; + pageInfo = pageInfo || { + current: toPageCurrent, + previous: innerCurrent.value, + pageSize: innerPageSize.value, + }; - setInnerCurrent(current, pageInfo); - props.onChange?.(pageInfo); - } + setInnerCurrent(toPageCurrent, pageInfo); + props.onChange?.(pageInfo); }; const handlePageChange = (type: PageChangeType) => { @@ -190,36 +182,33 @@ export default defineComponent({ const pageSize = Number(val); const newPageCount = pageSize > 0 ? Math.max(Math.ceil(props.total / pageSize), 1) : 1; - const indexExceeds = innerCurrent.value > newPageCount; - // 用户自主控制 - const userControlled = current.value != null && current.value < newPageCount; + const previousCurrent = innerCurrent.value; + const indexExceeds = previousCurrent > newPageCount; - // 初始 pageInfo(用于 setInnerPageSize 时传参) - const initialPageInfo = { - current: indexExceeds ? newPageCount : innerCurrent.value, - previous: innerCurrent.value, + // 触发 onPageSizeChange 回调 + setInnerPageSize(pageSize, { + current: indexExceeds ? newPageCount : previousCurrent, + previous: previousCurrent, pageSize, - }; - - setInnerPageSize(pageSize, initialPageInfo); + }); + // 场景:用户在 onPageSizeChange 中修改 current,需要重新计算 current nextTick(() => { - if (indexExceeds) { - // 当当前页索引超过新页数时,需要跳转到合适页 - const pageCurrent = userControlled ? newPageCount : innerCurrent.value; - const pageInfo = { - current: pageCurrent, - previous: initialPageInfo.current, - pageSize, - }; - toPage(pageCurrent, pageInfo); - } else { - const pageInfo = { - current: innerCurrent.value, - previous: initialPageInfo.current, - pageSize, - }; + const userChanged = innerCurrent.value !== previousCurrent; + const targetCurrent = userChanged ? innerCurrent.value : indexExceeds ? newPageCount : innerCurrent.value; + + const pageInfo = { + current: targetCurrent, + previous: previousCurrent, + pageSize, + }; + + // 如果用户改了 current 或者不需要跳页,直接触发 onChange + // 否则需要调用 toPage 来更新内部状态 + if (userChanged || !indexExceeds) { props.onChange?.(pageInfo); + } else { + toPage(targetCurrent, pageInfo); } }); }; From 72ff65b7acdaec8d8bae1ebb37b3db33de4f2cb2 Mon Sep 17 00:00:00 2001 From: RSS1102 Date: Mon, 24 Nov 2025 18:48:46 +0800 Subject: [PATCH 6/7] fix(pagination): format code --- packages/components/pagination/pagination.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/components/pagination/pagination.tsx b/packages/components/pagination/pagination.tsx index 5b6d72b791..6573763d58 100755 --- a/packages/components/pagination/pagination.tsx +++ b/packages/components/pagination/pagination.tsx @@ -140,9 +140,7 @@ export default defineComponent({ watch( () => innerCurrent.value, - (val) => { - jumpIndex.value = val; - }, + (val) => (jumpIndex.value = val), ); const toPage: (pageIndex: number, pageInfo?: PageInfo) => void = (pageIndex, pageInfo) => { From fa00d3d34a8e0012e0e59a0ac73c4737abc478cc Mon Sep 17 00:00:00 2001 From: tdesign-bot Date: Mon, 24 Nov 2025 12:26:28 +0000 Subject: [PATCH 7/7] chore: stash changelog [ci skip] --- packages/tdesign-vue-next/.changelog/pr-6163.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 packages/tdesign-vue-next/.changelog/pr-6163.md diff --git a/packages/tdesign-vue-next/.changelog/pr-6163.md b/packages/tdesign-vue-next/.changelog/pr-6163.md new file mode 100644 index 0000000000..7eee33748f --- /dev/null +++ b/packages/tdesign-vue-next/.changelog/pr-6163.md @@ -0,0 +1,6 @@ +--- +pr_number: 6163 +contributor: RSS1102 +--- + +- fix(table): 修复分页受控模式下 `current` 属性手动变更不触发 `onPageChange` 的问题 @RSS1102 ([#6163](https://github.com/Tencent/tdesign-vue-next/pull/6163))