Hooks

coderljw 2024-10-13 React
  • React
  • Hooks
大约 1 分钟

# 1. Antd-Table 自适应屏幕高度

import { useContext, useEffect, useRef } from 'react'
import { ConfigProvider } from 'antd'
import type { AdaptiveParams, UseAntTableAdaptiveParams } from './types'

export { AdaptiveParams, UseAntTableAdaptiveParams }

const useAntTableAdaptive = (params: UseAntTableAdaptiveParams = {}) => {
  const {
    minHeight = 0,
    compensateHeight = 0,
    screenSelector,
    tableSelector = 'body',
    drawer,
    drawerSelector = 'body',
  } = params === true ? ({} as AdaptiveParams) : params
  const { getPrefixCls } = useContext(ConfigProvider.ConfigContext)
  const preWindowHeight = useRef<number>(window.innerHeight)
  const preContainerHeight = useRef<number>()
  const prefixCls = getPrefixCls()

  const updateHeight = (screenContainer: HTMLElement, tableContainer: HTMLElement) => {
    const antTableBody = tableContainer.querySelector(`.${prefixCls}-table-body`) as HTMLElement
    const antTableTBody = tableContainer.querySelector(`.${prefixCls}-table-tbody`) as HTMLElement
    const antTablePlaceholder = tableContainer.querySelector(
      `.${prefixCls}-table-placeholder`,
    ) as HTMLElement
    if (!antTableBody && !antTableTBody) return
    const tableBodyHeight = (antTableBody || antTableTBody).offsetHeight

    const containerHeight = screenContainer.scrollHeight
    const windowHeight = window.innerHeight
    if (containerHeight === windowHeight) return

    const calcHeight = tableBodyHeight - (containerHeight - windowHeight) - compensateHeight
    const height = Math.max(minHeight, calcHeight)

    if (antTableBody) antTableBody.style.maxHeight = `${height}px`
    if (antTablePlaceholder) antTablePlaceholder.style.height = `${height}px`
  }

  const getScreenContainer = (container: HTMLElement | null) => {
    const screenContainer = screenSelector && document.querySelector(screenSelector)
    const drawerContainer =
      drawer && (container || document.body).querySelector(`.${prefixCls}-drawer-wrapper-body`)
    return (screenContainer || drawerContainer || document.body) as HTMLElement
  }

  const modifyDrawerHeight = (container: HTMLElement | null) => {
    const drawerContent = container?.querySelector(`.${prefixCls}-drawer-content`) as HTMLElement
    const drawerWrapperBody = container?.querySelector(
      `.${prefixCls}-drawer-wrapper-body`,
    ) as HTMLElement

    if (drawerContent) drawerContent.style.overflow = 'unset'
    if (drawerWrapperBody) drawerWrapperBody.style.height = 'auto'
  }

  useEffect(() => {
    if (params !== true && !(typeof params === 'object' && params !== null)) return
    const drawerContainer = document.querySelector(drawerSelector) as HTMLElement
    const tableContainer = document.querySelector(tableSelector) as HTMLElement
    const screenContainer = getScreenContainer(drawerContainer)
    if (!tableContainer) return
    if (drawer) modifyDrawerHeight(drawerContainer)

    const ro = new ResizeObserver(([container]) => {
      const offsetHeight = (container.target as HTMLElement).offsetHeight
      if (offsetHeight === preContainerHeight.current) return
      preContainerHeight.current = offsetHeight
      updateHeight(screenContainer, tableContainer)
    })
    ro.observe(screenContainer)

    const onresize = () => {
      if (window.innerHeight === preWindowHeight.current) return
      preWindowHeight.current = window.innerHeight
      updateHeight(screenContainer, tableContainer)
    }
    window.addEventListener('resize', onresize)

    return () => {
      ro.unobserve(screenContainer)
      window.removeEventListener('resize', onresize)
    }
  }, [])
}

export default useAntTableAdaptive
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
  • types.ts
export interface AdaptiveParams {
  /**
   * @name 最小高度
   * @default 0
   */
  minHeight?: number
  /**
   * @name 补偿高度
   * @desc 当底部有fixed元素时使用
   * @default 0
   */
  compensateHeight?: number
  /**
   * @name 全屏包裹容器选择器
   * @default body
   * @example '#adaptive-screen'
   */
  screenSelector?: string
  /**
   * @name table包裹容器选择器
   * @desc 当页面中有多个Table时使用,定位Table
   * @example '#adaptive-table'
   */
  tableSelector?: string
  /**
   * @name Drawer容器
   * @desc 当Table在Drawer容器中时使用,会修改drawer-wrapper-body的height为`auto`
   */
  drawer?: boolean
  /**
   * @name drawer包裹容器选择器
   * @desc 当页面中有多个Drawer时使用,定位Drawer
   * @example '#adaptive-drawer'
   */
  drawerSelector?: string
}

export type UseAntTableAdaptiveParams = AdaptiveParams | true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
以父之名
周杰伦.mp3