Skip to content

Commit

Permalink
feat: scrollY 自动计算
Browse files Browse the repository at this point in the history
  • Loading branch information
Barrior committed Jun 14, 2024
1 parent 1182802 commit c5573b1
Show file tree
Hide file tree
Showing 9 changed files with 238 additions and 47 deletions.
24 changes: 8 additions & 16 deletions examples/search-table-react/020-table-height.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,25 @@ import { sleep } from '@examples/utils'
import schema from './helpers/schema'
import columns from './helpers/columns'
import createDataSource from './helpers/createDataSource'

// 引入 Search
import SearchTable from '@schema-render/search-table-react'

const Demo = () => {
return (
<SearchTable
style={{
// 保证 SearchTable 高度存在
height: 500,
}}
search={{ schema }}
table={{
columns,
showRowNumber: true,
// 开启自动滚动 Y 轴计算
autoScrollY: true,
}}
request={async (searchParams) => {
// 打印搜索条件
console.log('searchParams:', searchParams)

// 模拟请求接口获取表格数据
await sleep()
const data = createDataSource()

// 返回表格数据渲染
return {
// 表格数据
data,
// 数据总数,用于分页
total: 100,
}
const data = createDataSource(searchParams.pageSize)
return { data, total: 100 }
}}
/>
)
Expand Down
30 changes: 24 additions & 6 deletions packages/search-table-react/src/SearchTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import { Table } from 'antd'
import type { Ref } from 'react'
import { forwardRef, useEffect, useImperativeHandle, useRef } from 'react'

import { EClassNames } from './constants'
import useColumns from './hooks/useColumns'
import useRequest from './hooks/useRequest'
import useScrollY from './hooks/useScrollY'
import useSearch from './hooks/useSearch'
import type { ISearchTableProps, ISearchTableRef } from './typings/index.d'

Expand All @@ -25,7 +27,7 @@ const SearchTable = (
titleTop,
title,
titleBottom,
table,
table = {},
footer,
}: ISearchTableProps,
ref: Ref<ISearchTableRef>
Expand All @@ -40,6 +42,9 @@ const SearchTable = (
table,
})

// 表格高度计算:“一屏显示”效果
const { scrollY, updateScrollY } = useScrollY({ table, rootElemRef })

// 数据请求处理
const {
loading,
Expand All @@ -52,13 +57,20 @@ const SearchTable = (
searchValueRef,
table,
request,
updateScrollY,
})

// 搜索栏
const { handleSearchChange, handleSearchReset, handleSearchSubmit } = useSearch({
const {
handleSearchChange,
handleSearchReset,
handleSearchSubmit,
handleToggleCollapsed,
} = useSearch({
searchValueRef,
search,
runRequest,
updateScrollY,
})

// 组件加载完毕请求一次数据
Expand Down Expand Up @@ -87,6 +99,7 @@ const SearchTable = (
setDataSource(data)
forceUpdate()
},
updateScrollY,
}))

const comRenderParams = { loading }
Expand All @@ -98,7 +111,7 @@ const SearchTable = (
style={{
display: 'flex',
flexDirection: 'column',
rowGap: 10,
rowGap: 20,
...style,
}}
>
Expand All @@ -112,19 +125,23 @@ const SearchTable = (
onChange={handleSearchChange}
onReset={handleSearchReset}
onSubmit={handleSearchSubmit}
onToggleCollapsed={handleToggleCollapsed}
/>

{titleTop?.(comRenderParams)}

<div className={`${prefixCls}-title`}>
<div>{title?.tabsRightContent?.(comRenderParams)}</div>
</div>
{title?.tabs && (
<div className={`${prefixCls}-title`}>
<div>{title?.tabsRightContent?.(comRenderParams)}</div>
</div>
)}

{titleBottom?.(comRenderParams)}

<Table
tableLayout="fixed"
{...table}
className={classNames(table.className, EClassNames.table)}
columns={finalColumns}
dataSource={dataSource}
loading={{
Expand All @@ -135,6 +152,7 @@ const SearchTable = (
scroll={{
scrollToFirstRowOnChange: true,
x: 'max-content',
y: scrollY,
...table?.scroll,
}}
/>
Expand Down
38 changes: 18 additions & 20 deletions packages/search-table-react/src/constants/index.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,10 @@
/**
* 内置 Action 名称
*/
export const ACTIONS = {
submit: 'submit',
reset: 'reset',
collapse: 'collapse',
} as const
import { createRandomId } from '../utils/common'

const clsUid = createRandomId()

/**
* 默认参数
* 列配置 key
*/
export const DEFAULT_SEARCH_TABLE_PROPS = {
prefixCls: 'schema-render',
layoutColumnGap: 10,
layoutRowGap: 15,
actions: [ACTIONS.reset, ACTIONS.submit, ACTIONS.collapse],
defaultCollapsed: true,
collapsedRows: 2,
}

export type ISearchTableDefaultProps = typeof DEFAULT_SEARCH_TABLE_PROPS

export enum EColumnsKeys {
/**
* 操作栏
Expand All @@ -31,3 +15,17 @@ export enum EColumnsKeys {
*/
rowNumber = '__row-number__',
}

/**
* 内部使用类名
*/
export const EClassNames = {
/**
* 表格根节点类名
*/
table: `st-table-${clsUid}`,
/**
* 表格分页节点类名
*/
pagination: `st-pagination-${clsUid}`,
}
26 changes: 21 additions & 5 deletions packages/search-table-react/src/hooks/useRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,33 @@ import type { TablePaginationConfig } from 'antd'
import type { MutableRefObject } from 'react'
import { useRef, useState } from 'react'

import { EClassNames } from '../constants'
import type {
IRequestOptions,
IRequestParams,
IRequestResult,
ISearchTableProps,
ISearchTableRef,
} from '../typings/index.d'

const { logger, pick } = utils
const { logger, pick, classNames } = utils

interface IUseRequest {
request: ISearchTableProps['request']
updateScrollY: ISearchTableRef['updateScrollY']
table: ISearchTableProps['table']
searchValueRef: MutableRefObject<IObjectAny>
}

/**
* 数据请求模块
*/
export default function useRequest({ request, table, searchValueRef }: IUseRequest) {
export default function useRequest({
request,
updateScrollY,
table,
searchValueRef,
}: IUseRequest) {
// 分页参数
const paginationRef = useRef({ current: 1, pageSize: 10, total: 0 })
// 请求参数
Expand Down Expand Up @@ -100,28 +108,36 @@ export default function useRequest({ request, table, searchValueRef }: IUseReque

setLoading(false)

// 请求完毕后,更新表格高度,即 scrollY 值
if (table.autoScrollY) {
updateScrollY()
}

// 返回数据
return result
}
)

let innerPagination: ISearchTableProps['table']['pagination'] = false as const

if (table?.pagination !== false) {
if (table.pagination !== false) {
innerPagination = {
style: { marginBottom: 0 },
showQuickJumper: true,
showSizeChanger: true,
...table?.pagination,
...table.pagination,
...paginationRef.current,
onChange: (current: number, pageSize: number) => {
// 触发外部事件
;(table?.pagination as TablePaginationConfig)?.onChange?.(current, pageSize)
;(table.pagination as TablePaginationConfig)?.onChange?.(current, pageSize)
// 设置分页数据
Object.assign(paginationRef.current, { current, pageSize })
// 重新拉取数据
runRequest()
},

// 添加特有类名,用于 scrollY 计算
className: classNames(table.pagination?.className, EClassNames.pagination),
}
}

Expand Down
81 changes: 81 additions & 0 deletions packages/search-table-react/src/hooks/useScrollY.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { useMemoizedFn, utils } from '@schema-render/core-react'
import type { RefObject } from 'react'
import { useEffect, useRef, useState } from 'react'

import { EClassNames } from '../constants'
import type { ISearchTableProps } from '../typings/index.d'
import { forEach } from '../utils/common'
import { calcOuterHeight, getNumericStyleValue } from '../utils/dom'

const { isUndefined } = utils

interface IUseScrollYParams {
table: ISearchTableProps['table']
rootElemRef: RefObject<HTMLElement>
}

/**
* 表格高度自动适配计算方案:“一屏显示”
*/
export default function useScrollY({ table, rootElemRef }: IUseScrollYParams) {
const [scrollY, setScrollY] = useState<number | undefined>(undefined)
const timerRef = useRef<ReturnType<typeof setTimeout>>()

const calcScrollY = useMemoizedFn(() => {
if (!rootElemRef.current || !isUndefined(table.scroll?.y)) {
return
}

const tableElem = rootElemRef.current.querySelector(`.${EClassNames.table}`)
const theadElem = tableElem?.querySelector('thead')
const paginationElem = tableElem?.querySelector(`.${EClassNames.pagination}`)

// 内容元素的总高度
let elementsHeight = 0

forEach(rootElemRef.current.children, (child) => {
// 表格元素的内容高度这里排除,需要单独计算
if (child !== tableElem) {
elementsHeight += calcOuterHeight(child as HTMLElement)
}
})

// 加上表头高度
elementsHeight += calcOuterHeight(theadElem)

// 加上分页高度
elementsHeight += calcOuterHeight(paginationElem as HTMLElement)

// 加上 rowGap 的高度
const rowGap = getNumericStyleValue(rootElemRef.current, 'rowGap')
elementsHeight += rowGap * (rootElemRef.current.children.length - 1)

// 设置 scrollY 的值
setScrollY(rootElemRef.current.clientHeight - elementsHeight)
})

/**
* 更新 scrollY
*/
const updateScrollY = useMemoizedFn((delay = 0) => {
clearTimeout(timerRef.current)
timerRef.current = setTimeout(calcScrollY, delay)
})

/**
* 窗口变化,表格高度重新计算
*/
useEffect(() => {
if (!table.autoScrollY) {
return
}
const handleResize = () => updateScrollY()
window.addEventListener('resize', handleResize)
return () => window.removeEventListener('resize', handleResize)
}, [])

Check warning on line 75 in packages/search-table-react/src/hooks/useScrollY.ts

View workflow job for this annotation

GitHub Actions / testing

React Hook useEffect has missing dependencies: 'table.autoScrollY' and 'updateScrollY'. Either include them or remove the dependency array

return {
scrollY,
updateScrollY,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ interface IUseSearchParams {
search: ISearchProps
searchValueRef: MutableRefObject<IObjectAny>
runRequest: ISearchTableRef['refresh']
updateScrollY: ISearchTableRef['updateScrollY']
}

const { hasOwnProperty } = utils
Expand All @@ -20,6 +21,7 @@ export default function useSearch({
searchValueRef,
search,
runRequest,
updateScrollY,
}: IUseSearchParams) {
const { forceUpdate } = useForceUpdate()

Expand Down Expand Up @@ -60,9 +62,17 @@ export default function useSearch({
await runRequest()
})

// 收起、展开事件
const handleToggleCollapsed = useMemoizedFn((isCollapsed: boolean) => {
search.onToggleCollapsed?.(isCollapsed)
// 更新表格高度
updateScrollY()
})

return {
handleSearchChange,
handleSearchReset,
handleSearchSubmit,
handleToggleCollapsed,
}
}
5 changes: 5 additions & 0 deletions packages/search-table-react/src/typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,9 @@ export interface ISearchTableRef {
* 清除搜索
*/
clearSearchValue: () => void
/**
* 更新表格高度以达到“一屏显示”效果
* @param delay 延迟计算时间
*/
updateScrollY: (delay?: number) => void
}
Loading

0 comments on commit c5573b1

Please sign in to comment.