实现 antd table 自动调整可视高度

19,215 阅读4分钟

一. 应用场景

最近在做的项目中有大量的表格,正常的表格高度是没有限制的,数据量很大的时候会出现表格内容以及分页信息超出可视窗口, 为了查看超出的部分就需要滚动页面但是这样就会把查询条件等信息滚出可视窗口.

原文地址:实现 antd table 自动调整可视高度 - 掘金 (juejin.cn)

滚动后的页面:

而产品经理又想要把所有信息都同时展现在页面中.这样就需要给表格内容设置一个固定的高度,怎么实现呢?

二.Table scroll 属性的应用

这个还是比较简单实现的,因为antd Table 有一个属性scroll:

  <Table
      columns={columns}
      dataSource={data}
      scroll={{y:600}}
    />    

其中这个y的值可以是number,也可以是string,输入特定的数字是能限制高度,但是对不同的屏幕尺寸适配不太好, 因此可以使用动态计算 css3 calc() 方法实现: scroll={{y:'calc(100vh - 400px)'}} 当然这个400px 是屏幕中除了表格内容以外的高度,需要计算和调试才能得到 看到这里几乎一般的这种需求(表格比较少的页面)就能解决了,但是如果只是这样我也就没必要专门这么多的篇幅去记录了...

三.事情的转折

正当我辛辛苦苦把每个页面的Table都这样计算调试好后,本来以为就可以完美收官了,这时传来了一个噩耗: 产品经理觉得表格上方的布局间隙太大影响了表格内容的展示所以需要统一调小点, 调节上边布局事小,但是会影响到表格内容展示的高度,需要把每个表格的srcoll.y重新进行调整,这要是十几个页面一个个去调节, 在加上说不定啥时候上边的布局又有调整还不得把人累死,所以干脆想个一劳永逸的方法

四.自动计算表格内容的高度

主要思路就是通过js动态获取表格内容上方的高度,可以获取Table的标题栏Header的底部距离顶部的高度
至于获取元素到顶部的距离可以使用 getBoundingClientRect() 来实现
getBoundingClientRect方法的官方解释:

Element.getBoundingClientRect() 方法返回元素的大小及其相对于视口的位置。

话不多说直接上代码: utils/utils.js

/**
 * 获取第一个表格的可视化高度
 * @param {number} extraHeight 额外的高度(表格底部的内容高度 Number类型,默认为74) 
 * @param {reactRef} ref Table所在的组件的ref
 */
export function getTableScroll({ extraHeight, ref }={}) {
  if (typeof extraHeight == "undefined") {
    //  默认底部分页64 + 边距10
    extraHeight = 74
  }
  let tHeader = null
  if (ref && ref.current) {
    tHeader = ref.current.getElementsByClassName("ant-table-thead")[0]
  } else {
    tHeader = document.getElementsByClassName("ant-table-thead")[0]
  }
  //表格内容距离顶部的距离
  let tHeaderBottom = 0
  if (tHeader) {
    tHeaderBottom = tHeader.getBoundingClientRect().bottom
  }
  // 窗体高度-表格内容顶部的高度-表格内容底部的高度
  // let height = document.body.clientHeight - tHeaderBottom - extraHeight
  let height = `calc(100vh - ${tHeaderBottom + extraHeight}px)`
  // 空数据的时候表格高度保持不变,暂无数据提示文本图片居中
  if (ref && ref.current) {
    let placeholder = ref.current.getElementsByClassName('ant-table-placeholder')[0]
    if (placeholder) {
      placeholder.style.height = height
      placeholder.style.display = "flex"
      placeholder.style.alignItems = "center"
      placeholder.style.justifyContent = "center"
    }
  }
  return height
}

单个Table的 引用:

import { getTableScroll } from '@/utils/utils'
// 设置成0,防止页面抖动
 const [scrollY, setScrollY] = useState(0)
  //页面加载完成后才能获取到对应的元素及其位置
 useEffect(() => {
    setScrollY(getTableScroll())
  }, [])

 <Table
    columns={columns}
    dataSource={data}
    scroll={{y:scrollY}} 
 /> 

创建一个公共的组件 conponents/ScrollTable.js

import React, { useEffect, useState, useRef } from 'react';
import { getTableScroll } from '@/utils/utils'
import { Table, } from 'antd';

export default function (props) {
    const [scrollY, setScrollY] = useState(0)
    let countRef = useRef(null);
    useEffect(() => {
        let scrolly = getTableScroll({ ref: countRef })
        setScrollY(scrolly)
    }, [props])
    return <div ref={countRef} >
    	 {/* 保留Table的其他属性以及scroll.x */}
        <Table {...props} scroll={{ x: props.scroll?.x, y: scrollY }} />
    </div >
}

引用 ScrollTable:

import ScrollTable from './conponents/ScrollTable'
 ...
<ScrollTable
	...
    columns={columns}
    dataSource={data}
/> 

做到这里算是告一段落了,目前只想到了这个方法.

最近在研究npm包的发布,就拿这个功能做了个npm包 scroll-antd-table 发布了下做了个实验,感兴趣的可以去看看

scroll-antd-table npm 包地址

scroll-antd-table git 地址

advanced-antd - npm (npmjs.com)

朋友们要是有更好的方法也欢迎留言,谢谢了~