V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
simonguo
V2EX  ›  前端开发

开源 UI 库中,唯一同时实现了大表格虚拟化和树表格的 Table 组件

  •  
  •   simonguo · 2019-01-18 13:20:04 +08:00 · 2662 次点击
    这是一个创建于 2143 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景

    有这样一个需求,一位 React Suite (以下简称 rsuite)的用户,他需要一个 Table 组件能够像 Jira Portfolio 一样,支持树形数据,同时需要支持大数据渲染。 截止到目前( 2019 年 1 月 17 日)为止,开源 UI 库中没有找到可以支持的组件,所以 rsuite 在最新的版本中支持这一特性。

    接下来,我们看一下 rsuite 中是怎么支持这两个功能?

    大表格虚拟化

    首先,我们看一下支持大数据渲染,在页面中渲染过多的 DOM 元素会带来性能问题,必须得有一种解决方案去优化它,我们暂且叫做大表格虚拟化。

    所谓的大表格虚拟化,其实就是为表格设置一个较大的数据(比如 10000 条数据),然后虚拟一个表格隐藏掉不需要显示的数据。

    为了解决让浏览器渲染的大量 DOM 时候出现的性能问题,我们不能把 10000 条数据都渲染到页面,采用一种方式,只渲染可视范围内数据。 同时为表格设置一个滚动条,只有在滚动到需要显示的区域时候才渲染该区域的数据,减少的 DOM 数量。

    预览地址

    以上这是一个 10000 条数据的 Table,渲染后的 HTML 结构是:

    我们可以看到在 Table 中只渲染了 14 个 rs-table-row ,其中第一个和最后一个是没有 children, 只是一个拥有高度的占位符。 每一个 rs-table-row 都是绝对定位,所以即使 Table 中删除一个 Row, 或者新增一个 Row ,也不会改变其他 Row 的位置。 在这样的基础上,通过获取滚动条的滚动的位置,就很容易判断当前 Row 的 top 值是否在 Table 的可视范围内,同时更新所有的 Row。

    很多优秀的库都实现了这样的功能,原理基本一致,比如 react-virtualized 就提供 Table 组件,但是他不支持 Tree。

    树形表格

    在表格中展示树形数据的需求,我们见得比较多就像甘特图表格展示那样。它有子父层级关系,可以展开子节点。

    这样一个表格,很多 Table 组件都支持,但是如果同时需要支持虚拟化就相对比较麻烦,因为在展开关闭节点的时候需要重新计算显示的 DOM 以及设置滚动条的位置。

    rsuite Table 组件之前的版本中,渲染的树形表格的 DOM 结构是一棵 Tree。 所以首先需要把 Tree 拍平,转换一个一维数组,为每一个节点设置父节点,通过父节点的深度渲染 Tree 节点的相对位置。 然后就比较好处理,只需要在点击展开关闭节点按钮的时候,处理好数据的过滤。

    安装与使用

    rsuite 的 Table 组件的设计,对开发还是非常方便,通过 <Table><Column><Cell><HeaderCell> 组件定义结构,通过赋值data 属性渲染表格数据。

    安装

    npm install rsuite --save
    

    如果你在项目只希望用到 Table, 不想安装整个 rsuite 库,你可以单独安装 rsuite-table

    示例代码:

    import { Table } from 'rsuite';
    
    const { Column, HeaderCell, Cell } = Table;
    const data = [{ id: 1, name: 'foobar', email: '[email protected]' }];
    
    ReactDOM.render(
      <Table height={400} data={data}>
        <Column width={70} align="center" fixed>
          <HeaderCell>编号</HeaderCell>
          <Cell dataKey="id" />
        </Column>
        <Column width={200} fixed>
          <HeaderCell>姓名</HeaderCell>
          <Cell dataKey="name" />
        </Column>
        <Column width={200}>
          <HeaderCell>邮箱</HeaderCell>
          <Cell dataKey="email" />
        </Column>
      </Table>
    );
    

    最后

    最后,对于一个成熟的 Table 组件怎么能只有这点功能,所以它还支持:

    • 自定义调整列宽
    • 锁定列
    • 自动换行
    • 排序
    • 分页
    • 编辑
    • 合并单元格
    • 自定义单元格
    • 自动列宽
    • 可展开行

    剩下唯一的问题,就是您是否在项目中尝试它。

    4 条回复    2019-01-18 13:47:34 +08:00
    agdhole
        1
    agdhole  
       2019-01-18 13:29:03 +08:00 via Android
    这个需求让我想到了上次的帖子“技术选型开除前端”
    xiwangzishi
        2
    xiwangzishi  
       2019-01-18 13:38:11 +08:00
    @agdhole 哈哈哈,是的。
    fy
        3
    fy  
       2019-01-18 13:40:43 +08:00
    @agdhole #1 记忆犹新
    chinvo
        4
    chinvo  
       2019-01-18 13:47:34 +08:00
    @agdhole #1 印象深刻
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2832 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 07:38 · PVG 15:38 · LAX 23:38 · JFK 02:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.