在 React-Native 中像 antd-table 一样实现表格布局

3,339 阅读4分钟

1 为什么要做

公司内部APP开发使用的技术栈是react-native ,在需求中,涉及报表模块,出现了比较多的表格展示部分, 功能包括表格单元内容需要自定义、列冻结、横向纵向滚动条、展开子表格。

本想找一个配置化的 RN 表格组件,但是找了一圈下来,发现现有的组件拆分颗粒度、功能、样式等都不能全部满足自己的全部需求;

也咨询了其他同学,有建议通过 Webview 直接写 web 版 antd-table,这样最省心;但是同时也有一个问题,这样调试起来可能就比较费劲了,特别是涉及到数据交互这一块,所以选择了放弃。

本着追求极致的目标,为了交付最符合业务场景的表格,就选择自己撸(程序猿的天性....hhhhhhhh....造起来).

27977e3787e78259c1c83322da6dfcd3.jpg

为了保证开发效率,也为了产品大大合理的开发周期要求,选择了在 react-native-table-component 这个包的基础上进行开发(站在巨人的肩膀上,万分感谢作者),同时在使用中也对渲染性能做了深度优化和改进,下面就让我为大家介绍一下吧。

2 组件库名称

react-native-beautiful-table

2.1 介绍

这是一个 api 类似 antd-table 的 react-native Table 布局组件库,它的特点就是用配置化的方式快速搭建复杂表格

2.2 功能描述

  • api 配置化,并提供一定的基础样式,同时支持修改;
  • 支持内容全部自定义;
  • 支持列冻结;
  • 支持行点击后展开收起及渲染子内容;
  • 支持支持列横向竖向滚动(包括列冻结时的滚动一致性)
  • 样式调整

2.3 使用示例

2.3.1 基本使用

import React from 'react';
import { View } from 'react-native';
import BeautifulTable from 'react-native-beautiful-table';

const demoPage = () => {

  const columns = [
    {
      title: '序号',
      dataKey: 'id',
      width: 50,
    },
    {
      title: '品牌',
      dataKey: 'brand',
      flex: 1
    },
    {
      title: '手机名',
      dataKey: 'name',
      flex: 1
    },
    {
      title: '模型',
      dataKey: 'model',
      align: 'right',
      flex: 1
    }
  ]

  const data = [
    {
      brand: '大米',
      name: '大米11',
      id: '1',
      model: '128+8'
    },
    { brand: '大米', name: '大米12', id: '2', model: '256+8' },
    { brand: 'redMi', name: 'redMi 10', id: '3', model: '256+12' },
    { brand: 'redMi', name: 'redMi 超级超级豪华至尊尊享王者版', id: '4', model: '256+12' }
  ]

  return (
    <View flex={1}>
     <BeautifulTable containerStyle={{paddingHorizontal: 20}} columns={columns} data={data} />
  </View>
  )
}

2.3.2 自定义内容 + 左侧列冻结

import React from 'react';
import { View, Text } from 'react-native';
import BeautifulTable from 'react-native-beautiful-table';

const demoPage = () => {

  const columns = [
    {
      title: '序号',
      dataKey: 'id',
      width: 200,
      // 此处为左侧列冻结配置,需要注意Table宽度需要大于屏幕宽度才会生效
      fixed: 'left'
    },
    {
    // header部分自定义,同时支持 JSX 和 render 方法渲染
      title: <Text>品牌</Text>,
      dataKey: 'brand',
      width: 200,
    },
    {
      title: '手机名',
      dataKey: 'name',
      width: 200,
      render (key, item) {
        return <Text>手机{key}</Text>
      }
    },
    {
      title: '模型',
      dataKey: 'model',
      align: 'right',
      width: 200,
    }
  ]

  const data = [
    {
      brand: '大米',
      name: <Text style={{ fontWeight: 'bold' }}>大米11</Text>,
      id: '1',
      model: '128+8',
    },
    { brand: '大米', name: '大米12', id: '2', model: '256+8' },
    { brand: 'redMi', name: 'redMi 10', id: '3', model: '256+12' },
    { brand: 'redMi', name: 'redMi 超级超级豪华至尊尊享王者版', id: '4', model: '256+12' }
  ]

  return (
    <View flex={1}>
     <BeautifulTable columns={columns} data={data} />
  </View>
  )
}

2.3.2 点击子列表展开

import React from 'react';
import { View, Text } from 'react-native';
import BeautifulTable from 'react-native-beautiful-table';

const demoPage = () => {

  const columns = [
    {
      title: '序号',
      dataKey: 'id',
      width: 200,
      fixed: 'left',
      render (key, item) {
        return <Text>自定义序号 {key}</Text>
      }
    },
    {
      title: <Text>品牌</Text>,
      dataKey: 'brand',
      width: 200,
    },
    {
      title: '手机名',
      dataKey: 'name',
      width: 200,
    },
    {
      title: '模型',
      dataKey: 'model',
      align: 'right',
      width: 200,
    }
  ]

  const data = [
    {
      brand: '大米',
      name: <Text style={{ fontWeight: 'bold' }}>大米11</Text>,
      id: '1',
      model: '128+8',
    },
    { brand: '大米', name: '大米12', id: '2', model: '256+8' },
    { brand: 'redMi', name: 'redMi 10', id: '3', model: '256+12' },
    // 文案超出宽度会换行,超出2行省略号
    { brand: 'redMi', name: 'redMi 超级超级豪华至尊尊享王者版', id: '4', model: '256+12' }
  ]

  return (
    <View flex={1}>
      <BeautifulTable
        columns={columns}
        data={data}
        // 可以控制是否展开子表格
        isExpandShow
        contentCellStyle={{ justifyContent: 'flex-start' }}
        filterSetRowStyle={(item, index) => {
          // 根据实际数据自定义某几项的样式
          return index === 1 && { backgroundColor: 'pink' }
        }}
        onContentRowPress={(item, index) => {
          alert('我点击了行')
        }}
        // 点击 table 后,展开子表格
        expandedRender={(item, index) => {
          return (
            <BeautifulTable
              // 隐藏表头这样才能看起来像一个表格有需要添加hideHeader
              columns={columns}
              data={data}
              containerStyle={{ backgroundColor: 'pink' }}
            />
          )
        }}
      />
  </View>
  )
}

组件属性

属性类型描述默认值
columnsColumnItem组件数据[]
dataobject数据内容[]
fieldKeystring数据唯一标识id
isExpandShowboolean是否默认展开拓展项false
defaultExpandIndexboolean默认展示的展开项索引

其他配置,如 headerbodyrowcell等样式调整api,具体参考 libs/index.d.ts  api ts 描述,里面有详细的介绍

ColumnItem 属性

属性类型描述默认值
dataKeystring键值名称
titlestringJSX.Element标题内容
flexnumber布局宽度占比1
widthnumber宽度具体值
align'left''center''right'文字对齐方式'left'
fixed'left''right'列冻结
render(text: string, row: ITableDataItem, index: number) => JSX.Element

文档链接: react-native-beautiful-table 功能还是比较强大的,可以做到横向+纵向+列冻结,那个场景过于华丽,就不把视频放出来了,可以私聊获取...HHHH

同时欢迎大家使用,有什么问题随时欢迎与我私信交流。

image.png


注意事项

  • ColCols 里的单元格无法做到每行自适应高度
  • 请在 textStyle 属性里设置 margin 值来调整内边距,不建议用 padding
  • 该组件使用Hooks api开发,所以你需要把你的React版本升级到+16.8