3

基于业务沉淀组件 => manage-table

2020年下半年,有几张图片刷屏:有人骑在自行车上看书,有人边骑车边用电脑,有人床上铺满了一摞摞书……“边骑车边用电脑”的同学被称为“卷王”登上热搜。 慢慢的这些同学毕业了,卷王带着卷走上了社会,带动了其他人一起卷,卷的人越来越多了,苦不堪言,就导致了一些重复造轮子和造一些毫无意义的轮子的现象出现。

造轮子,本来是件好事,但是随着内卷的出现,造轮子就慢慢演变成了一个极端,出现了凭空造轮子和重复造轮子的事情,既不能服务于业务,还使得内卷现象越来越严重,真正的苦不堪言。

分析当前业务遇到的问题,进而产生新的思路和总结,利用技术的手段提升工作效率,提高开发速度,才是真正的有意义的轮子,也不枉一场。

场景

CMS(content management system)一词出现已久,通常指的是内容管理系统,是一种位于WEB前端和后端办公系统或流程之间的软件系统。在开发cms后台的过程中,最最常用的应该就是Table了,例如 antd的table:

图片.png 这应该是最最常用的开发后台管理系统中使用到的组件了,没有个Table,都不好意思说是个cms系统。不过在稍微庞大的业务中会存在一个非常常见的问题,就是一个数据源会有很多很多字段需要进行展示,如果都展示出来呢,就会存在一个非常不美观且乱糟糟的感觉,眼花缭乱。同时不同的人,希望看到的字段也是不一样的,比如A同学希望看到标题0、1、2、3,B同学希望看到标题1、2、3、4,C同学希望看到标题7、8、9、10等。

这样就是一个非常个性化的需求了,如果希望后端同学来参与的话,就会增加后端同学的工作量,同时前端工作也不会相应的减少。得益于浏览器的localstorage存储能力,前端就可以实现,根本不需要后端同学的参与。

实现

首先,既然是antd的Table组件,我们肯定是要基于现有的功能去实现这个需求,所以我们需要在Table组件的基础上套一层,既不能影响Table的展示,同时还能够定制展示列。那我们就可以列一下需求了:

  1. 不影响Table的展示
  2. 可以选择自定义展示列
  3. 可以对展示列进行排序
  4. 不会对业务产生其他影响(这是最主要的)

需求既然已经明确,我们就可以开整了,具体的实现,就不多说了,我们可以看下实现后的效果:

图片.png

打磨

既然已经实现了最初的需求,就可以高枕无忧了。怎么可能呢?想太多了吧!!!

是的,后来产品说,现在数据展示列太多了,比之前多了三倍,想在对展示列进行选择的时候进行一下分组,不然都挤在一块密密麻麻的不好找,严重影响工作效率了

WTF!最见不得别人说影响工作效率了,这么严重的问题怎么现在才说,怎么不早点提需求过来呢?早点提过来肯定早就实现了啊,不会存在影响工作效率的问题啊.

啊!!!我可真是个口是心非的渣男,可是我知道,小蝌蚪才是渣男,我不配啊!!说多了都是泪啊,还是抓紧做需求吧。看下实现效果:

图片.png 嗯,完美,就是这么个效果。对Table的封装进行了二次修改,在不影响之前的使用方式的基础上,增加了对分组的能力支持,我可真TM棒!

> 然而,快乐的时光总是那么短暂啊~~

有一天,我们的另外一个平台发现,咦,你这个功能还怪好用嘞,能不能给我们也用用,好吧,最简单直接的方式是复制粘贴呀。复制粘贴到一半的时候,突然又来了一个人也想用用这个功能,WTMD就很头大。

这么说来,还是封装成一个npm包吧,等我会,我给你们发布成一个组件包,你们直接安装使用即可。

npm i manage-table
复制代码

尽管拿去用吧。

使用

安装

npm i manage-table
or
yarn add manage-table
复制代码

manage-table组件有对应的peerDependencies,如果没有安装的话,需要手动安装一下对应的依赖:

"peerDependencies": {
  "@ant-design/icons": "^4.6.4",
  "antd": "^4.12.0",
  "react": "^17.0.0",
  "react-beautiful-dnd": "^13.1.0"
}
复制代码

使用方式-: 直接引用,使用内置设置

代码如下:

import ManageTable  from "manage-table";
import './App.css';
import React from "react";

function App() {
  const mockColumns = new Array(50).fill('').map((_item: string, index) => {
    return {
      dataIndex: 'title' + index,
      key: 'title' + index,
      title: '标题' + index,
      show: index % 3 === 0,
    };
  });
  mockColumns.push({
    dataIndex: 'action',
    key: 'action',
    title: '操作',
    show: true,
  });
  return (
    <div className="App">
      <ManageTable name="testTable" columns={mockColumns}/>
    </div>
  );
}

export default App;
复制代码

效果如下:

图片.png

使用方式二:自定义header部分

代码如下:

import React from "react";
import { Button } from "antd";
import ManageTable from "manage-table";

export default function App2() {
  const mockColumns = new Array(50).fill("").map((_item, index) => {
    return {
      dataIndex: "title" + index,
      key: "title" + index,
      title: "标题" + index,
      show: index % 3 === 0
    };
  });
  mockColumns.push({
    dataIndex: "action",
    key: "action",
    title: "操作",
    show: true
  });
  const ref = React.createRef();
  const handleShowModal = () => {
    ref.current.showModal();
  };
  const SettingHeader = (
    <div style={{ textAlign: "left" }}>
      <Button onClick={handleShowModal}>自定义设置</Button>
    </div>
  );
  return (
    <div className="App">
      <ManageTable
        ref={ref}
        SettingComp={SettingHeader}
        name="testTable2"
        columns={mockColumns}
      />
    </div>
  );
}
复制代码

效果如下:

图片.png

使用方式三:分组展示

代码如下:

import React from "react";
import { Button } from "antd";
import ManageTable from "manage-table";

const mockGroup = () => {
  const data = new Array(4).fill('').map((_item:string, index: number) => {
    return {
      title: '分组' + index,
      records: new Array(10).fill('').map((_item: string, indx) => {
        return {
          dataIndex: 'title' + index + '_' + indx,
          key: 'title' + index + '_' + indx,
          title: '标题' + index + '_' + indx,
          show: indx % 5 === 0,
        };
      }),
    };
  });
  // 任何一个索引都可以,不必须是0
  data[0].records.push({
    dataIndex: 'action',
    key: 'action',
    title: '操作列',
    show: true,
  })
  return data;
}

export default function AppGroupRef() {
  const ref: any = React.createRef();

  const handleSet = () => {
    ref.current.showModal();
  }

  const SettingHeader = (
    <div style={{textAlign: 'left'}}>
      <Button type="primary" onClick={handleSet}>自定义设置</Button>
    </div>
  );
  return (
    <div className="App">
      <ManageTable ref={ref} SettingComp={SettingHeader} name="testTableGroup" columns={mockGroup()}/>
    </div>
  );
}
复制代码

效果如下:

图片.png

其他方式

除了可以上面三种方式使用之外,还支持固定展示的配置,即部分字段默认展示且不允许进行排序和删除。manage-table默认是存储在浏览器的缓存里面的,是跟随浏览器走的,如果不想走浏览器缓存,而是自定义存储的话,也是支持的。

具体如下:

ManageTable, 继承自antd的Table

参数名类型说明
namestring存储所使用的唯一的key,必传
columnsManageColumnType[]GroupManageColumn[]
refReact.createRef()的返回对象增加面板, 非必传
SettingCompReact.ReactNode自定义设置头部, 非必传
setTitleReact.ReactNode、string自定义弹窗的标题,默认'设置显示字段', 非必传
defaultShowKeysstring[]默认显示的字段,不需要进行选择or 排序
initialShowKeysstring[]初始显示的字段,自定义存储
onKeysSelected(keys: string[]) => void存储钩子函数,搭配自定义存储使用

ManageColumnType, 继承自antd的Table的ColumnType

参数名类型说明
showboolean是否默认显示

GroupManageColumn, 继承自antd的Table的ColumnType

参数名类型说明
titlestring组名,必传
recordsManageColumnType[]列数据, 必传

写在最后

欢迎使用和提交反馈。

团队

TNTWeb - 腾讯新闻前端团队,TNTWeb 致力于行业前沿技术探索和团队成员个人能力提升。为前端开发人员整理出了小程序以及 web 前端技术领域的最新优质内容,每周更新 ✨,欢迎 star,github 地址:https://github.com/tnfe/TNT-Weekly

image.png


TNTWEB
3.8k 声望8.5k 粉丝

腾讯新闻前端团队