Flutter 实现Element UI Table表格

1,083 阅读2分钟

2022-08-14 12-20-36.2022-08-14 12_23_07.gif

今天开始实现基于Flutter,仿写Element Table,flutter web 正式版已经很久很久,一直也没有像element,ant 这种组件库。 闲的无聊,仿写试一试!

基于 column row如果去写的话,感觉会陷入嵌套之地狱。我可不想为出师,而放弃!

就在Flutter Table 这个widget 上面二次开发,写了一个简单列子,之后在探究根本!


// 自行看看其效果,感觉就是平平无奇
Table(
  children: [
    TableRow(
        children: [
          Text('张三'),
          Text('男'),
          Text('20'),
        ]
    ),
  ],
)
<el-table :data="tableData" style="width: 100%">
    <el-table-column prop="date" label="日期" width="180"> </el-table-column>
    <el-table-column prop="name" label="姓名" width="180"> </el-table-column>
    <el-table-column prop="address" label="地址"> </el-table-column>
 </el-table>

接下来开始我们的二次封装之路,首先看看Element UI语法

对比两个语法,既然仿写就叫,Flutter端就叫 ElTable ElTableColumu

首先写出来需要的Model ElTableColumu 前两个参数就设置必填了

class ElTableColumn {
  final String prop;
  final String label;
  final int? width;
  ElTableColumn({required this.prop, required this.label, this.width});
}

ElTable 增加两个属性 children 就是表头,data 就是表数据呗!

class ElTable extends StatefulWidget {
  final List<ElTableColumn> children;
  final List<Map> data;

  ElTable({Key? key, required this.children, required this.data})
      : super(key: key);

  @override
  _ElTableState createState() => _ElTableState();
}

class _ElTableState extends State<ElTable> {
  @override
  Widget build(BuildContext context) {
    return Table(
      children: [],
    );
  }
}

自定义Table 简单实现,实现了简单效果

Table(
  children: [
    TableRow(
        //第一行样式 添加背景色
        children: widget.children.map((e) => Text(e.label)).toList()),
        for (int i = 0; i < widget.data.length; i++)
          TableRow(children: [
            for (int j = 0; j < widget.data[i].keys.length; j++)
              Text(widget.data[i][widget.data[i].keys.toList()[j]])
          ]),
  ],
)
ElTable(
  data: [
    {
      "date": '2016-05-02',
      "name": '王小虎',
      "address": '上海市普陀区金沙江路 1518 弄'
    },
    .... 此处省略
  ],
  children: [
    ElTableColumn(prop: "date", label: '出生日期'),
    ElTableColumn(prop: "name", label: '姓名'),
    ElTableColumn(prop: "address", label: '地址'),
  ],
)

实现简单效果,样式问题后续加入, 但是发现属性 data 里面 key 不对应的prop 会有问题!

截屏2022-08-13 15.19.35.png

解决data 里面key和prop 对应不上问题,思路就是重组 Map

List<Map> newData = [];

@override
void initState() {
  super.initState();
  for (Map item in widget.data) {
    Map newMap = {};
    List<String> keys = widget.children.map((e) => e.prop).toList();
    for (String key in keys) {
      newMap.putIfAbsent(key, () => item[key] ?? "");
    }
    print(newMap);
    newData.add(newMap);
  }
  setState(() {});
}

@override
Widget build(BuildContext context) {
  return Table(
    children: [
      TableRow(
          //第一行样式 添加背景色
          children: widget.children.map((e) => Text(e.label)).toList()),
      for (int i = 0; i < newData.length; i++)
        TableRow(children: [
          for (int j = 0; j < newData[i].keys.length; j++)
            Text(newData[i][newData[i].keys.toList()[j]])
        ]),
    ],
  );
}

完美

截屏2022-08-14 10.29.25.png

完了,又卡着**el-table-column** 宽度属性,等我细细研究起来

开启谷歌大法!

截屏2022-08-14 10.51.12.png

完美融合,接下来就是怎么根据 ElTableColumn,宽度传入的宽度,动态设置相应的的东西

columnWidths: {
  0: FixedColumnWidth(200),
  1: FlexColumnWidth(4),
  2: FlexColumnWidth(4),
},

完美实现代码,具体效果

Map<int, TableColumnWidth> getColumnWidths() {
  Map<int, TableColumnWidth> columnWidth = {};
  for (int i = 0; i < widget.children.length; i++) {
    if (widget.children[i].width != null) {
      if (widget.children[i].width! > 0) {
        columnWidth.putIfAbsent(
            i, () => FixedColumnWidth(widget.children[i].width!.toDouble()));
      }
    }
  }

  return columnWidth;
}

// Table 下面属性
columnWidths: getColumnWidths()


ElTableColumn(prop: "date", label: '出生日期', width: 100),
ElTableColumn(prop: "name", label: '姓名', width: 200),
ElTableColumn(prop: "address", label: '地址'),

截屏2022-08-14 11.40.34.png

简单的列子,感觉也是那么回事了~

😯 鼠标悬浮上,背景颜色发生变化。 开始研究研究......

TableRow 这个widget 上面有 decoration 属性, 可以直接设置color,也就是背景颜色

但是怎么设置鼠标选中事件那,下面精简了代码!

// 鼠标当前状态
int? MouseIndex;

// 背景眼
decoration: BoxDecoration(
    color: MouseIndex == i ? Color(0xFFf5f7fa) : null,
    border: Border(bottom: BorderSide(color: Color(0xFFdcdfe6)))),

// 事件处理
MouseRegion(
  onExit: (e) {
    setState(() {
      MouseIndex = null;
    });
  },
  onHover: (e) {
    if (MouseIndex != i) {
      setState(() {
        MouseIndex = i;
      });
    }
  },
)

具体用法就这样

ElTable(
  data: [
    {
      "name": '王小虎',
      "date": '2016-05-02',
      "address": '上海市普陀区金沙江路 1518 弄',
    },
    {
      "date": '2016-05-04',
      "name": '王二虎',
      "address": '上海市普陀区金沙江路 1517 弄'
    },
    {
      "date": '2016-05-01',
      "name": '王三虎',
      "address": '上海市普陀区金沙江路 1519 弄'
    },
    {
      "date": '2016-05-03',
      "name": '王四虎',
      "address": '上海市普陀区金沙江路 1516 弄'
    }
  ],
  children: [
    ElTableColumn(prop: "date", label: '出生日期', width: 100),
    ElTableColumn(prop: "name", label: '姓名', width: 200),
    ElTableColumn(prop: "address", label: '地址'),
  ],
)