Skip to content
This repository was archived by the owner on Apr 7, 2024. It is now read-only.

新增功能:表格支持滚动到指定位置 #295

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
3 changes: 2 additions & 1 deletion packages/ali-react-table/src/base-table/html-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,12 @@ export function HtmlTable({
rowProps?.className,
)

const key = internals.safeGetRowKey(primaryKey, row, rowIndex)
const trProps = {
...rowProps,
className: rowClass,
'data-rowindex': rowIndex,
id: `art-table-row-${key}`, // 添加id,可用于滚动精准定位或与其他地方
children: hozInfo.visible.map((descriptor) => {
if (descriptor.type === 'blank') {
return <td key={descriptor.blankSide} />
Expand All @@ -83,7 +85,6 @@ export function HtmlTable({
}),
}

const key = internals.safeGetRowKey(primaryKey, row, rowIndex)
if (Row != null && tbodyHtmlTag === 'tbody') {
return React.createElement(Row, { key, row, rowIndex, trProps })
} else {
Expand Down
121 changes: 121 additions & 0 deletions packages/ali-react-table/src/base-table/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,127 @@ export class BaseTable extends React.Component<BaseTableProps, BaseTableState> {
}
}

/**
* 定位滚动条
* @desc 优先级按参数顺序降序
* @param top 目标值
* @param element 目标元素
* @param rowKey 行主键
* @param rowIndex 行索引
* @param offset 纵向滚动偏移量,用于抵消固定表头
*/
scrollTo ({ top, element, rowKey, rowIndex, offset }
: { element: HTMLElement, top: number, rowKey: string, rowIndex: number, offset: number }
) {
if (top > -1) return this.scrollToValue(top)
if (element) return this.scrollToElement(element, offset)
if (rowKey) return this.scrollToRowKey(rowKey, offset)
if (rowIndex) return this.scrollToRowIndex(rowIndex, offset)
}

/**
* 定位到指定位置
* @desc 动态行高时如需精准定位,可以传入目标元素进行二次修正
* @param top 纵向滚动条位置
* @param selector 目标元素选择器
* @param offset 纵向滚动偏移量,用于抵消固定表头
*/
private scrollToValue (top: number, selector?: string, offset?: number) {
let view = this.artTableWrapperRef.current
if (view.clientHeight === view.scrollHeight) {
view = document.documentElement as HTMLDivElement
}
if (!selector) {
return view.scrollTop = top
}
const element = view.querySelector(selector)
// 目标元素真实存在时直接精准定位
if (element) {
return this.scrollToElement(element, offset)
}
view.scrollTop = top
// 延迟修正
setTimeout(() => {
this.scrollToElement(view.querySelector(selector), offset)
}, 16)
}

/**
* 定位到指定元素
* @desc 虚拟表格不应该直接使用该方法
* @param element
* @param offset 纵向滚动偏移量,用于抵消固定表头
*/
private scrollToElement (element: Element, offset?: number) {
if (!element) return
let view = this.artTableWrapperRef.current
if (view.clientHeight === view.scrollHeight) {
view = document.documentElement as HTMLDivElement
}
view.scrollTop = this.getScrollOffsetTop(element, view) + (offset || 0);
}

/**
* 定位到指定行
* @desc 树形表格有节点展开时不应该使用此方法
* @param rowIndex 行号(从1开始)
* @param offset 纵向滚动偏移量,用于抵消固定表头
*/
private scrollToRowIndex (rowIndex: number, offset?: number) {
const { cache } = this.rowHeightManager
const end = Math.min(rowIndex + 1, cache.length)
let scrollTop = 0
for (let i = 0; i < end; i++) {
scrollTop += cache[i]
}
this.scrollToValue(scrollTop, `[data-rowindex="${rowIndex}"]`, offset)
}

/**
* 根据primaryKey定位到指定行
* @desc 支持在树型表格中定位到未展开的节点,调用时应提前更新该节点的所有父节点key至openKeys中,并延迟调用该方法)
* @param rowKey 行主键
* @param offset 纵向滚动偏移量,用于抵消固定表头
*/
private scrollToRowKey (rowKey: string, offset?: number) {
const { dataSource } = this.props
const { cache } = this.rowHeightManager
const length = dataSource.length
const { primaryKey } = this.props
let scrollTop = 0
for (let i = 1; i < length; i++) {
scrollTop += cache[i]
if (dataSource[i][primaryKey as string] === rowKey) break
}
this.scrollToValue(scrollTop, `#art-table-row-${rowKey}`, offset)
}

/**
* 获取元素在滚动区域中的位置
* @desc 节选自:https://github.com/Stanko/animated-scroll-to
* @param element 目标元素
* @param view 滚动区域元素
* @private
*/
private getScrollOffsetTop (element: Element, view: Element): number {
return this.getElementOffset(element).top - this.getElementOffset(view).top;
}

private getScrollOffsetLeft (element: Element, view: Element): number {
return this.getElementOffset(element).left - this.getElementOffset(view).left;
}

private getElementOffset (element: any) {
let top = 0;
let left = 0;
do {
top += element.offsetTop || 0;
left += element.offsetLeft || 0;
element = element.offsetParent;
} while (element);
return { top, left };
}

/** 自定义滚动条宽度为table宽度,使滚动条滑块宽度相同 */
private updateStickyScroll() {
const { stickyScroll, artTable, stickyScrollItem } = this.domHelper
Expand Down
30 changes: 18 additions & 12 deletions packages/ali-react-table/src/pipeline/features/treeMode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ export interface TreeModeFeatureOptions {

/** 指定表格每一行元信息的记录字段 */
treeMetaKey?: string | symbol

/** 指定树节点所在列的code,匹配不到时默认第一列 */
treeColumnCode?: string
}

export function treeMode(opts: TreeModeFeatureOptions = {}) {
Expand Down Expand Up @@ -79,6 +82,7 @@ export function treeMode(opts: TreeModeFeatureOptions = {}) {
const iconIndent = opts.iconIndent ?? ctx.indents.iconIndent
const iconGap = opts.iconGap ?? ctx.indents.iconGap
const indentSize = opts.indentSize ?? ctx.indents.indentSize
const treeColumnCode = opts.treeColumnCode

return pipeline.mapDataSource(processDataSource).mapColumns(processColumns)

Expand Down Expand Up @@ -110,7 +114,10 @@ export function treeMode(opts: TreeModeFeatureOptions = {}) {
if (columns.length === 0) {
return columns
}
const [firstCol, ...others] = columns

columns = columns.slice()
const treeColIndex: number = !treeColumnCode ? 0 : Math.max(columns.findIndex(col => col.code === treeColumnCode), 0)
const firstCol: ArtColumn = columns[treeColIndex]

const render = (value: any, record: any, recordIndex: number) => {
const content = internals.safeRender(firstCol, record, recordIndex)
Expand Down Expand Up @@ -184,17 +191,16 @@ export function treeMode(opts: TreeModeFeatureOptions = {}) {
})
}

return [
{
...firstCol,
title: (
<span style={{ marginLeft: iconIndent + iconWidth + iconGap }}>{internals.safeRenderHeader(firstCol)}</span>
),
render,
getCellProps: clickArea === 'cell' ? getCellProps : firstCol.getCellProps,
},
...others,
]
columns[treeColIndex] = {
...firstCol,
title: (
<span style={{ marginLeft: iconIndent + iconWidth + iconGap }}>{internals.safeRenderHeader(firstCol)}</span>
),
render,
getCellProps: clickArea === 'cell' ? getCellProps : firstCol.getCellProps,
}

return columns
}
}
}
3 changes: 3 additions & 0 deletions packages/website/docs/pipeline/features/tree-mode.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ export interface TreeModeFeatureOptions {

/** 指定表格每一行元信息的记录字段 */
treeMetaKey?: string | symbol

/** 指定树节点所在列的code,匹配不到时默认第一列 */
treeColumnCode?: string
}
```

Expand Down
21 changes: 21 additions & 0 deletions packages/website/docs/table/api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,27 @@ function Cell({ row, rowIndex, column, colIndex, tdProps }) {
| `headerCellProps` | `React.ThHTMLAttributes` | 表头单元格的 props |
| `features` | `{ [key: string]: any }` | 功能开关标记,用于对表格功能进行拓展 |

## 滚动到指定位置

定位到行,支持普通、虚拟表格(固定、动态行高均可):
```js
tableRef.current.scrollTo({
top: 'number',
element: 'HTMLElement',
rowKey: 'string',
rowIndex: 'number',
offset: 'number'
})
````

| 字段 | 类型 | |
| ----------------- | ---------------------------------------------------------- |------------------------------------------------------------------------------------|
| `top` | `number` | 通过具体数值定位 |
| `element` | `HTMLElement` | 通过目标元素定位 |
| `rowKey` | `string` | 通过行数据的主键值定位,可用于树形虚拟表格中任意节点的定位。如需定位未展开的节点,可先根据此rowKey递归展开父节点,[详见示例](/examples/scroll-to)|
| `rowIndex` | `number` | 通过行索引定位 |
| `offset` | `number` | 纵向滚动偏移量,可用于抵消固定表头 |

## CSS 变量列表

`<BaseTable />` 中大部分样式都是通过 CSS variables 来定义的,你可以通过下面的方式对表格进行风格化:
Expand Down
5 changes: 5 additions & 0 deletions packages/website/docs/table/examples.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -343,3 +343,8 @@ function 表格页脚() {
)
}
```


### 滚动到指定位置

[完整示例](/examples/scroll-to)
1 change: 1 addition & 0 deletions packages/website/example-sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module.exports = {
'table',
'pipeline',
'big-data',
'scroll-to',
'theme',
{
type: 'category',
Expand Down
13 changes: 11 additions & 2 deletions packages/website/examples/pipeline.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as fusion from '@alifd/next'
import { Button } from '@alifd/next'
import { Button, Divider, Radio } from '@alifd/next'
import { ArtColumn, collectNodes, features, isLeafNode, useTablePipeline } from 'ali-react-table'
import {
columns1,
Expand All @@ -26,10 +26,11 @@ export default { title: 'pipeline 功能拓展' }

export function 树形表格() {
const [openKeys, onChangeOpenKeys] = useState(['4', '4-2'])
const [treeColumnCode, setTreeColumnCode] = useState('title')
const pipeline = useTablePipeline({ components: fusion as any })
.input({ dataSource: dataSource4, columns: columns4 })
.primaryKey('id')
.use(features.treeMode({ openKeys, onChangeOpenKeys }))
.use(features.treeMode({ openKeys, onChangeOpenKeys, treeColumnCode }))

const allParentKeys = collectNodes(dataSource4, 'pre')
.filter((row) => !isLeafNode(row))
Expand All @@ -41,6 +42,14 @@ export function 树形表格() {
<Button onClick={() => onChangeOpenKeys(allParentKeys)}>展开全部</Button>
<Button onClick={() => onChangeOpenKeys([])}>收拢全部</Button>
</Button.Group>
<Divider direction="ver" />
树节点所在列:
<Radio.Group
shape="button"
defaultValue={treeColumnCode}
onChange={(v: any) => setTreeColumnCode(v)}
dataSource={columns4.slice(0, 4).map(({ code, name }: any) => ({ label: name, value: code }))}
/>
<p>
openKeys: {openKeys.join(', ')} {openKeys.length === 0 && '[空]'}
</p>
Expand Down
11 changes: 11 additions & 0 deletions packages/website/examples/scroll-to.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
id: scroll-to
title: 滚动到指定位置
hide_table_of_contents: true
hide_title: true
---

import * as stories from './scroll-to.stories.tsx'
import { Stories } from './helpers/Stories'

<Stories stories={stories} path="scroll-to.stories.tsx" />
Loading