diff --git a/packages/components/config/src/defaultConfig.ts b/packages/components/config/src/defaultConfig.ts index 564921c10..b6a6c18d5 100644 --- a/packages/components/config/src/defaultConfig.ts +++ b/packages/components/config/src/defaultConfig.ts @@ -285,6 +285,7 @@ export const defaultConfig: GlobalConfig = { childrenKey: 'children', getKey: 'key', size: 'md', + scrollToTopOnChange: true, pagination: { position: 'bottomEnd', }, diff --git a/packages/components/config/src/types.ts b/packages/components/config/src/types.ts index fc4147b2a..2bb47d81c 100644 --- a/packages/components/config/src/types.ts +++ b/packages/components/config/src/types.ts @@ -483,6 +483,7 @@ export interface TableConfig { */ rowKey?: string size: TableSize + scrollToTopOnChange?: boolean emptyCell?: string | ((options: TableEmptyCellOptions) => VNodeChild) diff --git a/packages/components/table/docs/Api.zh.md b/packages/components/table/docs/Api.zh.md index 796594906..4fc4daf9e 100644 --- a/packages/components/table/docs/Api.zh.md +++ b/packages/components/table/docs/Api.zh.md @@ -21,6 +21,7 @@ | `headless` | 是否隐藏表头 | `boolean` | `false` | - |- | | `pagination` | 配置分页器, 参见[TablePagination](#TablePagination) | `boolean \| TablePagination` | - | ✅ | 设置 `false` 时表示不显示分页 | | `scroll` | 表格滚动配置项,可以指定滚动区域的宽、高, 参见[TableScroll](#TableScroll) | `TableScroll` | - | - | - | +| `scrollToTopOnChange` | 是否在表格的分页、筛选、排序信息改变后滚动到顶部 | `boolean` | `true` | ✅ | - | | `size` | 表格大小 | `'lg' \| 'md' \| 'sm'` | `md` | ✅ |- | | `spin` | 表格是否加载中 | `boolean \| SpinProps` | - | - | - | | `tableLayout` | 表格元素的 [table-layout](https://developer.mozilla.org/zh-CN/docs/Web/CSS/table-layout) 属性 | `'auto' \| 'fixed'` | - | - | 固定表头/列或设置了 `column.ellipsis` 时,默认值为 `fixed` | diff --git a/packages/components/table/src/Table.tsx b/packages/components/table/src/Table.tsx index 9df0814b6..a33d33523 100644 --- a/packages/components/table/src/Table.tsx +++ b/packages/components/table/src/Table.tsx @@ -22,6 +22,7 @@ import { useFilterable } from './composables/useFilterable' import { useGetRowKey } from './composables/useGetRowKey' import { usePagination } from './composables/usePagination' import { useScroll } from './composables/useScroll' +import { useScrollOnChange } from './composables/useScrollOnChange' import { useSelectable } from './composables/useSelectable' import { useSortable } from './composables/useSortable' import { useSticky } from './composables/useSticky' @@ -46,6 +47,8 @@ export default defineComponent({ const mergedGetKey = useGetRowKey(props, config) const mergedEmptyCell = computed(() => props.emptyCell ?? config.emptyCell) const mergedSize = computed(() => props.size ?? config.size) + const { mergedPagination } = usePagination(props, config, mergedSize) + const stickyContext = useSticky(props) const scrollContext = useScroll(props, mergedAutoHeight, stickyContext) const columnsContext = useColumns(props, slots, config, scrollContext.scrollBarSizeOnFixedHolder) @@ -53,19 +56,23 @@ export default defineComponent({ const filterableContext = useFilterable(columnsContext.flattedColumns) const expandableContext = useExpandable(props, columnsContext.flattedColumns) const tableLayout = useTableLayout(props, columnsContext, scrollContext, stickyContext.isSticky) - const { mergedPagination } = usePagination(props, config, mergedSize) + + const { activeSorters } = sortableContext + const { activeFilters } = filterableContext const dataContext = useDataSource( props, mergedChildrenKey, mergedGetKey, - sortableContext.activeSorters, - filterableContext.activeFilters, + activeSorters, + activeFilters, expandableContext.expandedRowKeys, mergedPagination, ) const selectableContext = useSelectable(props, locale, columnsContext.flattedColumns, dataContext) + useScrollOnChange(props, config, scrollContext.scrollBodyRef, mergedPagination, activeSorters, activeFilters) + const context = { props, slots, diff --git a/packages/components/table/src/composables/useScrollOnChange.ts b/packages/components/table/src/composables/useScrollOnChange.ts new file mode 100644 index 000000000..df006eff3 --- /dev/null +++ b/packages/components/table/src/composables/useScrollOnChange.ts @@ -0,0 +1,59 @@ +/** + * @license + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE + */ + +import type { TablePagination, TableProps } from '../types' +import type { ActiveFilter } from './useFilterable' +import type { ActiveSorter } from './useSortable' +import type { TableConfig } from '@idux/components/config' + +import { type ComputedRef, type Ref, type WatchStopHandle, computed, watch } from 'vue' + +import { type VirtualScrollInstance, scrollToTop } from '@idux/cdk/scroll' + +export function useScrollOnChange( + props: TableProps, + config: TableConfig, + scrollBodyRef: Ref, + mergedPagination: ComputedRef, + activeSorters: ComputedRef, + activeFilters: ComputedRef, +): void { + const mergedScrollToTopOnChange = computed(() => props.scrollToTopOnChange ?? config.scrollToTopOnChange) + + let stopOnChangeWatch: WatchStopHandle | undefined + const startOnChangeWatch = () => { + stopOnChangeWatch = watch( + [() => mergedPagination.value?.pageIndex, () => mergedPagination.value?.pageSize, activeSorters, activeFilters], + () => { + if (!scrollBodyRef.value) { + return + } + + if (props.virtual) { + ;(scrollBodyRef.value as VirtualScrollInstance).scrollTo(0) + } else { + scrollToTop({ + target: scrollBodyRef.value as HTMLElement, + top: 0, + }) + } + }, + ) + } + + watch( + mergedScrollToTopOnChange, + scrollToTopOnChange => { + stopOnChangeWatch?.() + + if (scrollToTopOnChange) { + startOnChangeWatch() + } + }, + { immediate: true }, + ) +} diff --git a/packages/components/table/src/types.ts b/packages/components/table/src/types.ts index 456502be9..035ae1645 100644 --- a/packages/components/table/src/types.ts +++ b/packages/components/table/src/types.ts @@ -54,6 +54,7 @@ export const tableProps = { size: { type: String as PropType, default: undefined }, spin: { type: [Boolean, Object] as PropType, default: undefined }, sticky: { type: [Boolean, Object] as PropType, default: undefined }, + scrollToTopOnChange: { type: Boolean, default: undefined }, tableLayout: { type: String as PropType<'auto' | 'fixed'>, default: undefined }, virtual: { type: Boolean, default: false }, diff --git a/packages/pro/table/src/types.ts b/packages/pro/table/src/types.ts index cc030fe03..1aaf7f220 100644 --- a/packages/pro/table/src/types.ts +++ b/packages/pro/table/src/types.ts @@ -59,6 +59,7 @@ export const proTableProps = { layoutTool: { type: [Boolean, Object] as PropType, default: true }, pagination: { type: [Boolean, Object] as PropType, default: undefined }, scroll: { type: Object as PropType, default: undefined }, + scrollToTopOnChange: { type: Boolean, default: undefined }, size: { type: String as PropType, default: undefined }, spin: { type: [Boolean, Object] as PropType, default: undefined }, sticky: { type: [Boolean, Object] as PropType, default: undefined },