table组件

471 阅读2分钟

1、用法

在使vue或者react中,经常会用到table组件,它实现了一些功能封装。
一般我们只要传入行数据和列数据,即可实现页面渲染,下面我们讨论一下基本思想。

  • 勾选列、排序、展开折叠行
  • 固定某些列
  • 多级表头,搜索过滤
  • 表尾合计行
import { Space, Table, Tag } from 'antd';
import React from 'react'; 
const columns = [ 
    { title: 'Name', dataIndex: 'name', key: 'name', render: (text) => <a>{text}</a>, }, 
    { title: 'Age', dataIndex: 'age', key: 'age', }, 
    { title: 'Address', dataIndex: 'address', key: 'address', }, 
    { title: 'Tags', key: 'tags', dataIndex: 'tags', render: (_, { tags }) =>( 
        <> { tags.map((tag) => { 
            let color = tag.length > 5 ? 'geekblue' : 'green'; 
            if (tag === 'loser') { 
                color = 'volcano'; 
            } 
            return ( <Tag color={color} key={tag}> {tag.toUpperCase()} </Tag> )
          })
       }</> ), 
    }, 
    { title: 'Action', key: 'action', render: (_, record) => ( 
        <Space size="middle"> <a>Invite {record.name}</a> <a>Delete</a> </Space> ), 
    },
  ]; 
const data = [ 
      { key: '1', name: 'John Brown', age: 32, address: 'New York No. 1 Lake Park', tags: ['nice', 'developer'], }, 
      { key: '2', name: 'Jim Green', age: 42, address: 'London No. 1 Lake Park', tags: ['loser'], }, 
      { key: '3', name: 'Joe Black', age: 32, address: 'Sidney No. 1 Lake Park', tags: ['cool', 'teacher'], }, 
]; 
const App = () => <Table columns={columns} dataSource={data} />; 
export default App;

2、实现分析

如react-element,table目录下主要有如下文件

2.1 TableStore

最外层为TableStore组件,它主要是

  • 存储公共数据状态,如 columns、fixedColumns、data、currentRow、selectedRows、sortOrder等,并通过getChildContext共享给子组件;
  • 暴露的method,如toggleRowSelection 、toggeleRowExpanded等,并通过dispatchEvent方法来触发给外层组件
  • updataData和updataColumns等方法更新公共数据
  • render TableLayout组件

2.2 TableLayout

主要负责页面布局时的数据计算

  • 维护布局数据,如 表宽度、表头表体表尾高度、横向纵向滚动距离 等,并通过getChildContext共享给子组件;
  • 生命周期执行scheduleLayout函数计算布局数据
scheduleLayout()=>{
   this.setState(this.caculateWidth(),()=>{
      this.updateHeight()
      this.updataScrollY()
    }
}
  • render Table组件

2.3 Table

  • 分为三个table、左固定fixedColumns、正常table、右固定rightFixedColumns,其中左固定和右固定是TableStore中计算的,如果有这两部分则绘制;
  • 每个table分为三部分,TableHeader、TableBody、TableFooter,其中多级表头、搜索过滤、点击排序等在TableHeader中实现、表尾合计在TableFooter中实现;
  • 三个table布局数据进一步处理
  • syncScroll实现同步滚动,横向滚动时表尾表头scrollLeft同步改变,纵向滚动时左右固定表格scrollTop同步改变

2.4 TableBody

  • 渲染元素table组件,遍历data数组绘制tr节点,遍历columns数组绘制td节点;
  • 通过 colgroup和col标签控制表宽度;
  • tr和td确定一个cell单元格,执行column.render绘制单元格
  • 行和列点击会触发事件

3、拖动表格改变宽度

  • 使用react element组件自带该功能,在TableHeader组件中th列标签会监听onMouseMove、onMouseDown事件,进而重新计算列宽。
  • 使用react antd组件,表格缺少该功能,需要自己实现。
    实现方式为自定义 components.header.cell 即表头的列单元,给之包裹Reactable标签,监听onResize事件,重新计算columns数据里的width属性。
const ResizableTitle = (props: any) => {
    const {onResize, width, ...restProps} = props

    if (!width) {
        return <th {...restProps} />
    }
    return (
        <Resizable
            width={width}
            height={0}
            onResize={onResize}
            draggableOpts={{enableUserSelectHack: false}}
        >
            <th {...restProps} />
        </Resizable>
    )
}

欢迎关注我的前端自检清单,我和你一起成长