diff --git a/packages/core/table-core/scripts/smoke.mjs b/packages/core/table-core/scripts/smoke.mjs index be1a766..0faebbf 100644 --- a/packages/core/table-core/scripts/smoke.mjs +++ b/packages/core/table-core/scripts/smoke.mjs @@ -80,4 +80,43 @@ const before = table.getVisibleRows(); // memo 基线 table.dispatch({ type: 'clearSelection' }); // 无关状态变更 assert(table.getVisibleRows() === before, 'derive stages memoized across unrelated state changes'); +// —— 补充不变量 —— +const fresh = createTable({ + data: users, + columns: [{ key: 'name', header: 'Name', sortable: true }], + rowKey: 'id', + plugins: [paginationPlugin()], + initialState: { pagination: { page: 2, pageSize: 2 } }, +}); +assert( + fresh.getPageInfo().page === 2 && fresh.getPageInfo().pageSize === 2, + 'getPageInfo 无需先取可见行即返回 initialState 生效值', +); +assert(fresh.getPageInfo().totalPages === 3, 'getPageInfo 的 totalPages 由上游 total 推导'); + +const marks = createTable({ + data: users, + columns: [{ key: 'name', header: 'Name' }, { key: 'city', header: 'City' }], + rowKey: 'id', + plugins: [filterPlugin(), paginationPlugin(), selectionPlugin()], + initialState: { pagination: { page: 1, pageSize: 2 } }, +}); +marks.selectAllVisible(); // 选中第 1 页的 id 1 / 2 +marks.dispatch({ type: 'setFilter', key: 'city', value: 'Beijing' }); // 可见行整体换掉 +assert( + JSON.stringify(marks.getState().selection) === JSON.stringify([1, 2]), + 'selection 以 rowKey 记账,筛选换掉可见行后仍保留', +); + +const toggle = createTable({ + data: users, + columns: [{ key: 'age', header: 'Age', sortable: true }], + rowKey: 'id', + plugins: [sortPlugin()], +}); +toggle.dispatch({ type: 'toggleSort', key: 'age' }); +toggle.dispatch({ type: 'toggleSort', key: 'age' }); +toggle.dispatch({ type: 'toggleSort', key: 'age' }); +assert(toggle.getState().sorting.length === 0, '同一列连点三次回到无序(asc → desc → 取消)'); + console.log('SMOKE OK'); diff --git a/packages/core/table-core/src/plugins/pagination.ts b/packages/core/table-core/src/plugins/pagination.ts index bf37a0a..d281ebd 100644 --- a/packages/core/table-core/src/plugins/pagination.ts +++ b/packages/core/table-core/src/plugins/pagination.ts @@ -54,7 +54,10 @@ export function paginationPlugin(): TablePlugin { nextPage: () => table.dispatch({ type: 'setPage', page: pageInfo.page + 1 }), prevPage: () => table.dispatch({ type: 'setPage', page: pageInfo.page - 1 }), setPageSize: (pageSize: number) => table.dispatch({ type: 'setPageSize', pageSize }), - getPageInfo: (): PageInfo => ({ ...pageInfo }), + getPageInfo: (): PageInfo => { + table.getVisibleRows(); // 先跑一遍派生(内部有 memo),保证快照对应当前 state + return { ...pageInfo }; + }, }; }, }; diff --git a/packages/core/table-core/src/plugins/sort.ts b/packages/core/table-core/src/plugins/sort.ts index 8adc923..833735b 100644 --- a/packages/core/table-core/src/plugins/sort.ts +++ b/packages/core/table-core/src/plugins/sort.ts @@ -41,11 +41,13 @@ export function sortPlugin( case 'setSorting': return { ...state, sorting: action.sorting }; case 'toggleSort': { - const rules = action.multi ? [...state.sorting] : []; // 非 multi 直接单列重置 - const idx = rules.findIndex((r) => r.key === action.key); - if (idx === -1) rules.push({ key: action.key, dir: initialDir }); - else if (rules[idx].dir === 'asc') rules[idx] = { key: action.key, dir: 'desc' }; - else rules.splice(idx, 1); // desc 再点即取消 + const idx = state.sorting.findIndex((r) => r.key === action.key); // 本列当前方向的位置 + // 非 multi 只保留本列(单选语义),multi 保留全部列;不能一味清空,否则本列永远停在 asc + const rules = action.multi ? [...state.sorting] : idx === -1 ? [] : [state.sorting[idx]]; + const at = rules.findIndex((r) => r.key === action.key); + if (at === -1) rules.push({ key: action.key, dir: initialDir }); + else if (rules[at].dir === 'asc') rules[at] = { key: action.key, dir: 'desc' }; + else rules.splice(at, 1); // desc 再点即取消 return { ...state, sorting: rules }; } default: