Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions src/table/__tests__/pagination/onpage-scroll.test.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<TTable
rowKey="index"
data={this.data}
columns={[
{ title: 'index', colKey: 'index' },
{ title: 'applicant', colKey: 'applicant' },
]}
pagination={this.pagination}
on={{ 'page-change': onPageChange }}
></TTable>
);
},
});

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 (
<TTable
rowKey="index"
data={this.data}
columns={[
{ title: 'index', colKey: 'index' },
{ title: 'applicant', colKey: 'applicant' },
]}
pagination={this.pagination}
on={{ 'page-change': onPageChange }}
maxHeight={200}
></TTable>
);
},
});

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);
});
});
});
16 changes: 15 additions & 1 deletion src/table/base-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,23 @@ export default defineComponent({

const { showElement } = useElementLazyRender(tableRef, lazyLoad);

const resetScrollbar = () => {
Comment thread
RSS1102 marked this conversation as resolved.
Outdated
if (tableContentRef.value && tableContentRef.value.scrollTo) {
tableContentRef.value.scrollTo({ top: 0, left: 0, behavior: 'smooth' });
} else if (tableContentRef.value) {
// 兼容测试环境或旧浏览器
tableContentRef.value.scrollTop = 0;
tableContentRef.value.scrollLeft = 0;
}
};

const {
dataSource, innerPagination, isPaginateData, renderPagination,
} = usePagination(props, context);
} = usePagination(
props,
context,
resetScrollbar,
);

const onInnerResizeChange: BaseTableProps['onColumnResizeChange'] = (p) => {
props.onColumnResizeChange?.(p);
Expand Down
3 changes: 2 additions & 1 deletion src/table/hooks/usePagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export function usePaginationValue(
return [innerPagination, setInnerPagination];
}

export default function usePagination(props: TdBaseTableProps, context: SetupContext) {
export default function usePagination(props: TdBaseTableProps, context: SetupContext, resetScrollbar: () => void) {
const { pagination, disableDataPage, data } = toRefs(props);
const { classPrefix } = useConfig();
const dataSource = ref<TableRowData[]>([]);
Expand All @@ -67,6 +67,7 @@ export default function usePagination(props: TdBaseTableProps, context: SetupCon
// Vue3 ignore this line
context.emit('page-change', pageInfo, newData);
props.onPageChange?.(pageInfo, newData);
resetScrollbar();
};

const [innerPagination, setInnerPagination] = usePaginationValue(pagination, onPageChange);
Expand Down