From 88ff292047418aed7cacd8013bbd1a5145687e3e Mon Sep 17 00:00:00 2001 From: chaishi <974383157@qq.com> Date: Mon, 31 Jul 2023 15:38:56 +0800 Subject: [PATCH] feat(table): scrollToElement By row key --- src/common.ts | 4 ++++ src/table/_example/tree-select.vue | 25 +++++++++++++++----- src/table/_example/virtual-scroll.vue | 6 +++-- src/table/base-table.tsx | 22 +++++++++++++++-- src/table/enhanced-table.tsx | 34 ++++++++++++++++++++++++++- src/table/primary-table.tsx | 5 ++-- 6 files changed, 83 insertions(+), 13 deletions(-) diff --git a/src/common.ts b/src/common.ts index c0f66ed44..e8f794152 100644 --- a/src/common.ts +++ b/src/common.ts @@ -115,3 +115,7 @@ export interface ScrollToElementParams { time?: number; behavior?: 'auto' | 'smooth'; } + +export interface ComponentScrollToElementParams extends ScrollToElementParams { + key: string | number; +} diff --git a/src/table/_example/tree-select.vue b/src/table/_example/tree-select.vue index f3f70111e..0507cf8bd 100644 --- a/src/table/_example/tree-select.vue +++ b/src/table/_example/tree-select.vue @@ -170,19 +170,32 @@ export default { MessagePlugin.success('获取成功,请打开控制台查看'); }, + // 虚拟滚动场景:滚动到指定行 scrollToElement() { const { enhancedTableRef } = this.$refs; - const treeNodeData = enhancedTableRef.getData('first_level_150'); - console.log(treeNodeData); - // 因为可能会存在前面的元素节点展开,或行展开,故而下标跟序号不一定一样,不一定是 150 - enhancedTableRef.primaryTableRef.scrollToElement({ - // 跳转元素下标(第 151 个元素位置) - index: treeNodeData.rowIndex - this.selectedRowKeys.length, + + // 方式一:通过行唯一标识跳转到指定行 + enhancedTableRef.scrollToElement({ + // 滚动到指定元素 + key: 'first_level_150', + // 如果元素没有被展开,则跳转到父元素所在位置 + // key: 'second_level_1510', // 滚动元素距离顶部的距离(如表头高度) top: 47, // 高度动态变化场景下,即 isFixedRowHeight = false。延迟设置元素位置,一般用于依赖不同高度异步渲染等场景,单位:毫秒。(固定高度不需要这个) time: 60, }); + + // 方式二:通过行下标跳转到指定行(示例代码有效:勿删) + // const treeNodeData = enhancedTableRef.getData('first_level_150'); + // enhancedTableRef.primaryTableRef.scrollToElement({ + // // 跳转元素下标(第 151 个元素位置) + // index: treeNodeData.rowIndex - this.expandedRowKeys.length, + // // 滚动元素距离顶部的距离(如表头高度) + // top: 47, + // // 高度动态变化场景下,即 isFixedRowHeight = false。延迟设置元素位置,一般用于依赖不同高度异步渲染等场景,单位:毫秒。(固定高度不需要这个) + // time: 60, + // }); }, onRowClick(data) { diff --git a/src/table/_example/virtual-scroll.vue b/src/table/_example/virtual-scroll.vue index 4aec9d808..dd76f422d 100644 --- a/src/table/_example/virtual-scroll.vue +++ b/src/table/_example/virtual-scroll.vue @@ -93,8 +93,10 @@ export default { methods: { scrollToElement() { this.$refs.tableRef.scrollToElement({ - // 跳转元素下标(第 256 个元素位置) - index: 255, + // 方式一:使用下标跳转到指定行(第 256 个元素位置) + // index: 255, + // 方式二:使用行唯一标识跳转到指定行(id = 255) + key: 255, // 滚动元素距离顶部的距离(如表头高度) top: 47, // 行高度动态变化场景场景下,即 isFixedRowHeight = false。延迟设置元素位置,一般用于依赖不同高度异步渲染等场景,单位:毫秒。(固定高度不需要这个) diff --git a/src/table/base-table.tsx b/src/table/base-table.tsx index 6bac7af97..24586ea54 100644 --- a/src/table/base-table.tsx +++ b/src/table/base-table.tsx @@ -11,6 +11,7 @@ import { } from '@vue/composition-api'; import pick from 'lodash/pick'; import isFunction from 'lodash/isFunction'; +import get from 'lodash/get'; import props from './base-table-props'; import useTableHeader from './hooks/useTableHeader'; import useColumnResize from './hooks/useColumnResize'; @@ -32,7 +33,7 @@ import TFoot from './tfoot'; import log from '../_common/js/log'; import { getIEVersion } from '../_common/js/utils/helper'; import { getAffixProps } from './utils'; -import { Styles } from '../common'; +import { ComponentScrollToElementParams, Styles } from '../common'; import { BaseTableCol, TableRowData } from './type'; export const BASE_TABLE_EVENTS = ['page-change', 'cell-click', 'scroll', 'scrollX', 'scrollY', 'column-resize-change']; @@ -274,9 +275,26 @@ export default defineComponent({ addTableResizeObserver(tableRef.value); }); + const tableData = computed(() => (isPaginateData.value ? dataSource.value : props.data)); + + const scrollToElement = (params: ComponentScrollToElementParams) => { + let { index } = params; + if (!index && index !== 0) { + if (!params.key) { + log.error('Table', 'scrollToElement: one of `index` or `key` must exist.'); + return; + } + index = tableData.value?.findIndex((item) => get(item, props.rowKey) === params.key); + if (index < 0) { + log.error('Table', `${params.key} does not exist in data, check \`rowKey\` or \`data\` please.`); + } + } + virtualConfig.scrollToElement({ ...params, index }); + }; + return { virtualConfig, - scrollToElement: virtualConfig.scrollToElement, + scrollToElement, columnResizable, thList, classPrefix, diff --git a/src/table/enhanced-table.tsx b/src/table/enhanced-table.tsx index b8414bdb0..a6d4d37f8 100644 --- a/src/table/enhanced-table.tsx +++ b/src/table/enhanced-table.tsx @@ -7,12 +7,19 @@ import primaryTableProps from './primary-table-props'; import enhancedTableProps from './enhanced-table-props'; import PrimaryTable, { BASE_TABLE_ALL_EVENTS } from './primary-table'; import { - TdEnhancedTableProps, PrimaryTableCol, TableRowData, DragSortContext, TdPrimaryTableProps, + TdEnhancedTableProps, + PrimaryTableCol, + TableRowData, + DragSortContext, + TdPrimaryTableProps, + TableRowState, } from './type'; import useTreeData from './hooks/useTreeData'; import useTreeSelect from './hooks/useTreeSelect'; import { TableListeners } from './base-table'; import { usePrefixClass } from '../hooks/useConfig'; +import { ComponentScrollToElementParams } from '..'; +import log from '../_common/js/log'; const PRIMARY_B_EVENTS = [ 'cell-click', @@ -106,6 +113,30 @@ export default defineComponent({ context.emit('row-click', p); }; + const getScrollRowIndex = (rowStateData: TableRowState, key: string | number): number => { + if (!rowStateData) return -1; + if (rowStateData.rowIndex >= 0) return rowStateData.rowIndex; + if (rowStateData.rowIndex < 0) { + return getScrollRowIndex(rowStateData.parent, key); + } + }; + + const scrollToElement = (params: ComponentScrollToElementParams) => { + let { index } = params; + if (!index && index !== 0) { + if (!params.key) { + log.error('Table', 'scrollToElement: one of `index` or `key` must exist.'); + return; + } + const rowStateData = treeDataMap.value.get(params.key); + index = getScrollRowIndex(rowStateData, params.key); + if (index < 0 || index === undefined) { + log.error('Table', `${params.key} does not exist in data, check \`rowKey\` or \`data\` please.`); + } + } + primaryTableRef.value.scrollToElement({ ...params, index }); + }; + return { store, classPrefix, @@ -119,6 +150,7 @@ export default defineComponent({ onInnerSelectChange, onEnhancedTableRowClick, ...treeInstanceFunctions, + scrollToElement, }; }, diff --git a/src/table/primary-table.tsx b/src/table/primary-table.tsx index de3f67faa..d4fcaf2f0 100644 --- a/src/table/primary-table.tsx +++ b/src/table/primary-table.tsx @@ -22,6 +22,7 @@ import useEditableCell from './hooks/useEditableCell'; import useEditableRow from './hooks/useEditableRow'; import { EditableCellProps } from './editable-cell'; import useStyle from './hooks/useStyle'; +import { ComponentScrollToElementParams } from '../common'; export { BASE_TABLE_ALL_EVENTS } from './base-table'; @@ -293,8 +294,8 @@ export default defineComponent({ tRowAttributes, primaryTableClasses, errorListMap, - scrollToElement: (data: any) => { - primaryTableRef.value.virtualConfig.scrollToElement(data); + scrollToElement: (data: ComponentScrollToElementParams) => { + primaryTableRef.value.scrollToElement(data); }, scrollColumnIntoView: (colKey: string) => { primaryTableRef.value.scrollColumnIntoView(colKey);