STAY HUNGRY , STAY FOOLISH.

求知若饥,虚心若愚。

       浏览:

不一样的思维去封装Ant Design(一)

时间飞逝,转眼三个月过去了,自己博客也没更新过什么~
对不起,我怂了,怂了三个月没写博客。不是不想写,而是时间不是特别充足,很忙,也不知该如何写起。

  • 一.企业文化
  • 二.好的方面
  • 三.不好的方面
  • 四.初识UI库
    • 1.新建运力管理菜单及其所有模块
    • 2.实现司机信息页面基础表格
    • 3.实现司机信息页面刷新
    • 4.实现司机信息表格单行操作(查看、编辑、删除、复制、自定义)
    • 5.实现司机信息新增、批量、自定义操作
    • 6.实现司机信息模糊查询
    • 7.实现司机信息表格列表显隐;新增、编辑表单页自定义
    • 8.实现自定义配置
    • 9.整理组件通用性及功能实现
    • 10.分析核心组件BTable

一.企业文化

从我离职一家教育公司开始说起吧。记得当时那家公司的企业文化,简单的就三个字:
我对这三个字的理解:
包容、宽容身边的人和事
真诚、真心地为公司负责
做事、完成项目时三思而后行,先思考再执行

namibox

说实话,在那家公司自己也做到了这三点。
离职的原因无非就两个,一个是没成长(你给不了公司什么了),第二个是没价值(公司给不了你什么了)。


后面入职了一家创业公司,它的企业文化,也很简单,就三个词:坚韧职业相信
我对这三个词的理解:
坚韧地对待工作上的每一次挑战
把自己变得更加专业
相信自己、相信团队

gangfeng56

目前的我正在为这三点努力。只有当你认同公司的企业文化时,公司才会认同你。我在这家公司没有了以前先思考再执行的做事风格,而变成了先执行再思考,主要还是时间不够导致的。


二.好的方面

1.买车

6月份,喜提了自己人生的第一辆车,别克suv,尽管它是二手的,但我算是成为了有车一族。

bieke


也为它贴上了我的信仰:蒙奇·D·路飞,励志成为海贼王的男人:

bieke


2.拿毕业证

6月份,拿到了上海交通大学本科学历

shjt


shjt

牢记上海交通大学的校训:饮水思源,爱国荣校


三.不足的方面

最近不太顺心的点,可能就是工作上的事情。因为还得花时间去适应新的企业文化、新的业务方向、新的团队、新的ui库….在创业公司,追求高效率,效率高还不能导致质量下降,确实是件不容易的事情。我就喜欢挑战,所以来了~
公司后台管理系统主要技术栈是:react+react hooks+uix(基于Ant Design)+mobx

下面主要想说下这边的ui库,基于Ant Design的二次封装的uix,思想挺不错的,非常值得参考,就是需要时间去学习和揣摩其定义好的各种API,后面也会提及这样开发的优缺点。

首先看下核心组件BTable表格组件的分解图:

struct2

现在看不懂没关系,后面看完每个详细属性,回过头再看,会领悟该图的意义。


四.初识UI库

1.新建运力管理菜单及其所有模块

以新增运力模块举例,从下面原型图可知,该菜单下面有四个模块,分别是:承运人信息、车辆信息、司机信息、收款人信息。

transport_before

1.新增运力管理根文件夹:

创建transport文件夹到workbench:
/src/pages/workbench


2.在该文件夹下面创建子文件夹及文件:

struct

目录结构说明:

1
2
3
4
5
6
7
8
transport 运力管理
├── styles 运力相关样式
├── model 运力相关弹框
├── summary 运力相关每个tab详情页面
├── info.tsx 运力相关某个模块主页面(多个)
├── info_summary.tsx 运力相关某个模块tabs总详情页面(多个)
├── config.tsx 运力相关公共配置文件
└── routes.ts 运力相关路由

3.逐个实现它们,完成对routes.ts的定义

第一步,声明Routes,即运力相关url:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 工作台全局路由
export const Routes = {
...
// 运力管理
TransportRoot: '/work/transport/carrier',
TransportCarrier: '/work/transport/carrier/info',
TransportCarrierDetail: '/work/transport/carrier/detail',
TransportVehicle: '/work/transport/vehicle/info',
TransportVehicleDetail: '/work/transport/vehicle/detail',
TransportDriver: '/work/transport/driver/info',
TransportDriverDetail: '/work/transport/driver/detail',
TransportPayee: '/work/transport/payee/info',
TransportPayeeDetail: '/work/transport/carrier',
};

第二步,声明permissionOriginEnum,即一级菜单、二级菜单权限:

1
2
3
4
5
6
7
8
9
10
// 权限枚举
export const permissionOriginEnum = {
...
// 运力管理
M_ENT_CARRIER_MAIN: "LW_M_ENT_CARRIER_MAIN",
M_ENT_CARRIER_MAIN_TRANSPORTER: "LW_M_ENT_CARRIER_MAIN_TRANSPORTER",
M_ENT_CARRIER_MAIN_VEHICLE: "LW_M_ENT_CARRIER_MAIN_VEHICLE",
M_ENT_CARRIER_MAIN_DRIVER: "LW_M_ENT_CARRIER_MAIN_DRIVER",
M_ENT_CARRIER_MAIN_PAYEE: "LW_M_ENT_CARRIER_MAIN_PAYEE",
}

第三步,把每个模块的页面组件定义出来:
即承运人主页、详情页;车辆主页、详情页;司机主页、详情页;收款人主页、详情页。
carrier.tsx、carrierSummary.tsx、vehicle.tsx、vehicleSummary.tsx、
driver.tsx、driverSummary.tsx、payee.tsx、payeeSummary.tsx。

1
2
3
4
5
6
7
import React from "react"
function Carrier() {
return (
<div>Carrier</div>
)
}
export default Carrier

第四步,把前面声明过的路由、权限、组件全部用到,完成对routes.ts的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import { RouteVo } from "@bee/uix/typings"
import { lazy } from "react"
import { Routes } from "@/assets/config"
import { permissionOriginEnum } from "@/assets/config"

const carrier = lazy(() => import(/* webpackChunkName: "transport" */ "./carrier"))
const carrier_summary = lazy(() => import(/* webpackChunkName: "transport" */ "./carrierSummary"))
const vehicle = lazy(() => import(/* webpackChunkName: "transport" */ "./vehicle"))
const vehicle_summary = lazy(() => import(/* webpackChunkName: "transport" */ "./vehicleSummary"))
const driver = lazy(() => import(/* webpackChunkName: "transport" */ "./driver"))
const driver_summary = lazy(() => import(/* webpackChunkName: "transport" */ "./driverSummary"))
const payee = lazy(() => import(/* webpackChunkName: "transport" */ "./payee"))
const payee_summary = lazy(() => import(/* webpackChunkName: "transport" */ "./payeeSummary"));

export const transportRoutes: Array<RouteVo> = [
{
icon: "yunshu",
title: "运力管理",
path: Routes.TransportRoot,
permission: permissionOriginEnum.M_ENT_CARRIER_MAIN,
children: [
{
icon: "invoice_title",
title: "承运人信息",
component: carrier,
path: Routes.TransportCarrier,
permission: permissionOriginEnum.M_ENT_CARRIER_MAIN_TRANSPORTER,
},
{
hide: true,
icon: "invoice_title",
title: "承运人详情",
component: carrier_summary,
path: Routes.TransportCarrierDetail,
permission: permissionOriginEnum.M_ENT_CARRIER_MAIN_TRANSPORTER,
},
{
icon: "vehicle",
title: "车辆信息",
component: vehicle,
path: Routes.TransportVehicle,
permission: permissionOriginEnum.M_ENT_CARRIER_MAIN_VEHICLE,
},
{
hide: true,
icon: "vehicle",
title: "车辆详情",
component: vehicle_summary,
path: Routes.TransportVehicleDetail,
permission: permissionOriginEnum.M_ENT_CARRIER_MAIN_VEHICLE,
},
{
icon: "driver",
title: "司机信息",
component: driver,
path: Routes.TransportDriver,
permission: permissionOriginEnum.M_ENT_CARRIER_MAIN_DRIVER,
},
{
hide: true,
icon: "driver",
title: "司机详情",
component: driver_summary,
path: Routes.TransportDriverDetail,
permission: permissionOriginEnum.M_ENT_CARRIER_MAIN_DRIVER,
},
{
icon: "shoukuan",
title: "收款人信息",
component: payee,
path: Routes.TransportPayee,
permission: permissionOriginEnum.M_ENT_CARRIER_MAIN_PAYEE,
},
{
hide: true,
icon: "shoukuan",
title: "收款人详情",
component: payee_summary,
path: Routes.TransportPayeeDetail,
permission: permissionOriginEnum.M_ENT_CARRIER_MAIN_PAYEE,
},
],
},
]

最后渲染成功:

renderMenu


目录结构发生的变化:

transport_ok


2.实现司机信息页面基础表格

时间有限,我就以运力管理其中的一个模块,司机信息模块来举例说明

实现table的分页(切换上一页、下一页、跳页)、每页展示多少条(默认20条)、显示共多少条,刷新当前列表。
这四个table表格的基本功能,仅用简单的三个属性就能实现!它们分别是:titleurlfields

先看效果:

table_render


再看实现:

1
2
3
4
5
6
7
8
9
10
11
12
import React from "react"
import { BTable } from "@bee/uix"
function Driver() {
return (
<BTable
title="司机信息"
url="/logistics/web/enterprise/carrier/driver/findPage"
fields={[{...}]}
/>
)
}
export default Driver

title即表格唯一标识符,表格名称
url即表格分页请求接口
fields即需要展示的字段。(与接口字段一致)


下面是fields={[{…}]}的具体配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
fields={[
{
width: 70,
title: "序号",
dataIndex: "serialNumber",
render: (text, record, index) => <span>{index + 1}</span>,
},
{
width: 70,
title: 'ID',
dataIndex: 'id',
render: (text) => <span>{text || '--'}</span>,
},
{
width: 120,
title: '司机姓名',
dataIndex: 'name',
render: (text) => <span>{text || '--'}</span>,
}, {
width: 140,
title: '手机号',
dataIndex: 'mobileNo',
render: (text) => <span>{text || '--'}</span>,
}, {
width: 200,
title: "身份证号",
dataIndex: "idCardNo",
render: (text) => <span>{text || '--'}</span>,
}, {
width: 200,
title: "身份证地址",
dataIndex: "idCardAddress",
render: (text) => <span>{text || '--'}</span>,
}, {
width: 200,
title: "驾驶证号",
dataIndex: "driverLicenseNo",
render: (text) => <span>{text || '--'}</span>,
}]}

3.实现司机信息页面刷新

通过注入的refreshIdx变量自增1,去实现当前页面的刷新。
先看效果:

refresh


再看实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React, { useEffect, useRef } from "react"
import { BTable } from "@bee/uix"
import { TableHooks } from "@bee/uix/typings"

function Driver({ refreshIdx = 0 }) {
const hooks = useRef<TableHooks>(null);
useEffect(() => {
if (!refreshIdx) return;
hooks.current && hooks.current.refresh();
}, [refreshIdx]);
return (
<BTable
title="司机信息"
url="/logistics/web/enterprise/carrier/driver/findPage"
fields={[{...}]}
onTableHooks={_hooks => hooks.current = _hooks}
/>
)
}
export default Driver

4.实现司机信息表格单行操作(查看、编辑、删除、复制、自定义)

实现table的单行的复制、编辑、删除,通过简单的配置即可实现,也可以自定义单行操作,比如:查看日志。

通过配置hasRowOperate去显隐操作、detail去设置详情接口、rowFuncs去实现自定义单行操作。
先看效果:

rowFuncs

再看实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import React, { useEffect, useRef } from "react"
import { BTable, bTableFuncConfig } from "@bee/uix"
import { TableHooks } from "@bee/uix/typings"
import { transportDriverApis } from "@/api/transport.api";

function Driver({ refreshIdx = 0 }) {
...
return (
<BTable
...
url={transportDriverApis.list}
hasRowOperate={true}
detail={
{
key: "id",
url: transportDriverApis.detail,
}
}
rowFuncs={[{...}]}
/>
)
}
export default Driver

下面是rowFuncs={[{…}]}的具体配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
rowFuncs={
[
{
width: 50,
title: '查看',
method: bTableFuncConfig.extend,
render: record => (<BPopover
content={"查看"}
key={"set-permission"}
info={
<FIcon
size={17}
className="details"
name="l-details"
onClick={() => {
hooks.current.showDetail(record)
}}
/>
}
/>),
},
{
width: 50,
title: '编辑',
icon: commonTableIcons.edit(),
url: transportDriverApis.edit,
method: bTableFuncConfig.edit,
},
{
width: 50,
title: "删除",
icon: commonTableIcons.delete(),
url: transportDriverApis.delete,
method: bTableFuncConfig.delete
},
{
width: 50,
title: '复制',
icon: commonTableIcons.copy(),
url: transportDriverApis.add,
method: bTableFuncConfig.copy,
beforeStart: (row, config, callback) => enableTableFields(row, config, callback)
},
{
width: 50,
title: "日志",
method: bTableFuncConfig.extend,
render: record => <TableViewLog key={"tableViewLog"} operationEntityId={record.id} operationEntityType={'EnterpriseDriver'} />,
},
]
}

5.实现司机信息新增、批量、自定义操作

实现table的新增、批量删除、导入、导出,通过简单的配置即可实现,也可以自定义操作按钮。

通过配置isSelect去显隐表格左侧选择按钮、isSelectMultiple去定义左侧选择按钮是单选还是多选,batchFuncs去实现自定义操作。

先看效果:

batchFuncs


再看实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React, { useEffect, useRef } from "react"
import { BTable, bTableFuncConfig } from "@bee/uix"
import { TableHooks } from "@bee/uix/typings"
import { transportDriverApis } from "@/api/transport.api";

function Driver({ refreshIdx = 0 }) {
...
return (
<BTable
...
url={transportDriverApis.list}
isSelect={true}
isSelectMultiple={true}
batchFuncs={[{...}]}
/>
)
}
export default Driver

下面是batchFuncs={[{…}]}的具体配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
batchFuncs={[
{
url: transportDriverApis.add,
label: "新增",
method: bTableFuncConfig.add,
},
{
url: transportDriverApis.batchOperate,
label: "批量删除",
method: bTableFuncConfig.batchDelete,
query: { type: 'delete' },
},
{
url: transportDriverApis.import,
label: "导入",
method: bTableFuncConfig.import,
},
{
url: transportDriverApis.export,
label: "导出",
method: bTableFuncConfig.export,
},
{
url: transportDriverApis.batchOperate,
label: "批量禁用",
method: bTableFuncConfig.part,
query: { type: 'disabled' },
},
{
method: bTableFuncConfig.extend,
render: row => (
<Button
key={"extend-add"}
icon={commonTableIcons.add}
onClick={() => {
alert('自定义操作')
}}>
自定义操作
</Button>
),
}
]}

目前可以公共使用的属性:

1
2
3
4
5
6
7
8
9
10
11
12
// batchFuncs or rowFuncs 公共拓展方法属性
export const bTableFuncConfig = {
add: "add", // 新增
edit: "edit", // 编辑
copy: "copy", // 复制
delete: "delete", // 单条删除
batchDelete: "batchDelete", // 批量删除
part: "part", // 批量更新
import: "import", // 导入
export: "export", // 导出
extend: "extend", // 自定义操作
}

6.实现司机信息模糊查询

实现模糊查询,一般都是挨个写表单组件去实现,但这个是通过fields属性动态生成的。

通过在fields里面配置isFilter去显隐表单查询组件、filterSort去定义查询组件从左到右的顺序。

isFilter设置为ture的效果,默认和表单的字段倒序排放:

isFilter


filterSort设置为1、2、3…的效果,按照1、2、3的顺序排放:

filterSort


下面是fields={[{…}]}的具体配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
fields={[
{
width: 70,
title: "序号",
dataIndex: "serialNumber",
render: (text, record, index) => <span>{index + 1}</span>,
},
{
width: 70,
title: 'ID',
dataIndex: 'id',
render: (text) => <span>{text || '--'}</span>,
},
{
width: 120,
title: '司机姓名',
dataIndex: 'name',
render: (text) => <span>{text || '--'}</span>,
isFilter: true,
filterSort: 1,
}, {
width: 140,
title: '手机号',
dataIndex: 'mobileNo',
render: (text) => <span>{text || '--'}</span>,
isFilter: true,
filterSort: 2,
}, {
width: 200,
title: "身份证号",
dataIndex: "idCardNo",
render: (text) => <span>{text || '--'}</span>,
isFilter: true,
filterSort: 3,
}, {
width: 200,
title: "身份证地址",
dataIndex: "idCardAddress",
render: (text) => <span>{text || '--'}</span>,
isFilter: true,
filterSort: 4,
}, {
width: 200,
title: "驾驶证号",
dataIndex: "driverLicenseNo",
render: (text) => <span>{text || '--'}</span>,
isFilter: true,
filterSort: 5,
}]}

7.实现司机信息表格列表显隐;新增、编辑表单页自定义

表单生成出来,默认都是input。
但是我们可以继续设置当前字段使用的表单组件是input、select、img或其他,也可以设置当前字段是否为必填项、字段是否需要显隐到表单…

1.显隐控制:isHide、isFilter、isReadonly

isHide:true,表格字段隐藏

isHide_ok

想把序号、ID从表格中隐藏:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[{
width: 70,
title: "序号",
dataIndex: "serialNumber",
render: (text, record, index) => <span>{index + 1}</span>,
isHide: true,
},
{
width: 70,
title: 'ID',
dataIndex: 'id',
render: (text) => <span>{text || '--'}</span>,
isHide: true,
}]

isFilter:true,模糊查询字段显示

isFilter_ok

想把司机姓名这个条件去掉:

1
2
3
4
5
6
7
8
[{
width: 120,
title: '司机姓名',
dataIndex: 'name',
render: (text) => <span>{text || '--'}</span>,
// isFilter: true,
// filterSort: 1,
}]

isReadonly:true,表单添加、复制、编辑弹框字段隐藏

isReadOnly

想把序号、ID从表单中隐藏:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[{
width: 70,
title: "序号",
dataIndex: "serialNumber",
render: (text, record, index) => <span>{index + 1}</span>,
isHide: true,
isReadonly: true,
},
{
width: 70,
title: 'ID',
dataIndex: 'id',
render: (text) => <span>{text || '--'}</span>,
isHide: true,
isReadonly: true,
}]

最终效果:

o1


o2


2.特殊fields值

fields除了能够根据接口返回的字段返回响应的值外,还有以下几个用法。

1.序号
1
2
3
4
5
6
7
{
width: 70,
title: "序号",
dataIndex: "serialNumber",
isReadonly: true,
render: (text, record, index) => <span>{index + 1}</span>,
}

2.使用表单行组件
1
2
3
4
5
6
7
8
{
dataIndex: "licenseTime",
title: "驾驶证有效期",
placeholder: ["生效时间", "失效时间"],
input: bTableInputConfig.daterange,
filterProps: ["licenseStartTime", "licenseEndTime"],
isHide: true,
}

看驾驶证有效期,不是普通input,而是组件daterange。

o2

目前可以公共使用的组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
export const bTableInputConfig = {
divide: "divide", // 分隔
text: "text", // 普通input(默认值)
number: "number", // 数量input
switch: "switch", // 判断是或否
radio: "radio", // 单选
money: "money", // 钱input
percent: "percent", // 百分比input
tonnage: "tonnage", // 吨input
select: "select", // 下拉选择
selectasync: "select-async", // 下拉异步选择
date: "date", // 日期(年月日)
daterange: "daterange", // 日期范围(年月日)
datetime: "datetime", // 时间(年月日时分秒)
datetimerange: "datetimerange", // 时间范围(年月日时分秒)
json: "json", // 转出json字符串input
textarea: "textarea", // 多行文本框input
image: "image", // 图片
ocr: "ocr", // 图片识别
selectmap: "selectmap", // 地图选址
selectAddress: "selectAddress", //地址级联选择
extend: "extend", // 自定义拓展
}

3.自定义表单行
1
2
3
4
5
6
7
{
dataIndex: "tip",
title: "提示",
isHide: true,
input: bTableInputConfig.extend,
inputRender: text => <span style={{color:'red'}}>司机不能重复</span>
}

o2
看最后一个,只是个简单提示:司机不能重复。


8.实现自定义配置

该功能具体指的是可以通过穿梭框对筛选条件列表显示列表明细显示导出显示明细导出显示的字段进行显示和隐藏。
以列表显示举例,先看效果:

customSetting


再看实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import FTableConfig from "@/features/workbench/TableConfig"
// 原来的司机信息组件
function Driver() {...}
// 外面包的自定义配置组件
function CustomDriver() {
const [configVisible, setConfigVisible] = useState(false);
const hooks = useRef<TableHooks>(null);
return <FTableConfig
title={"司机信息自定义配置"}
visible={configVisible}
fields={fields}
config={{ type: "LOGISTICS_ENTERPRISE_DRIVER", ...tableConfigApis }}
onClose={() => setConfigVisible(false)}
onAfter={() => hooks.current && hooks.current.refresh()}
table={fields => <Driver fields={fields} setConfigVisible={setConfigVisible} />}
/>
}
export default CustomDriver

9.整理组件通用性及功能实现

熟练并掌握其属性及API,开发效率不快都难~

1.功能实现及对应所需字段:

功能实现 所需字段 设置值
页面刷新 refreshIdx -
表格 title、url、fields -
表格单行操作 hasRowOperate、detail、rowFuncs true
表格批量操作 isSelect、isSelectMultiple、batchFuncs true
表格模糊查询 isFilter、filterSort true
表格字段隐藏 isHide true
表单字段隐藏 isReadonly true

2.实现的公共弹框逻辑,基础的共8个:

功能实现 所需字段
新增 add
编辑 edit
删除 delete
批量删除 batchDelete
批量更新 part
复制 copy
导入 import
导出 export
功能扩展 extend

3.实现的公共表单组件,基础的共20个:

所需字段 功能实现 基于antd组件
text 输入框(普通) <Input type="text" />
money 输入框(金钱) <Input type="text" />
tonnage 输入框(吨数) <Input type="text" />
percent 输入框(百分比) <Input type="text" />
number 输入框(数量) <Input type="text" />
textarea 输入框(多行) <Input.TextArea />
json 输入框(转json字符串) <Input.TextArea />
switch 开关 <Switch />
radio 单选 <Radio>Radio</Radio>
date 日期选择 <DatePicker />
datetime 时间选择 <DatePicker />
daterange 日期范围选择 <DatePicker.RangePicker />
datetimerange 时间范围选择 <DatePicker.RangePicker />
select 下拉选择(同步) <Select />
selectasync 下拉选择(异步) <Select />
selectmap 地图选址 Input、Popover、Select、Spin 、高德地图web
selectAddress 地址级联选择 <Cascader/>
image 图片相关 Upload、message
ocr 图片识别相关 Carousel、Button
isDivide 分隔 Col span

10.分析核心组件BTable

只需要写配置文件,就能实现整个报表的基本功能,不得不说封装的ui库很强。
BTable分解示意图:

structs

可以发现,它把一个常见的表格页面,按照业务功能分解成对应组件,可以理解成业务组件,然后业务组件又是基于UI组件封装而成。

页面表格列头需要动态生成,于是封装了自定义设置组件FTableConfig
页面表格筛选查询需要动态生成,于是封装了顶部筛选组件BFilter
页面表格需要批量、自定义按钮操作,于是有了由多个Button按钮组成的批量操作区
页面表格需要主体和分页,于是有了由Table和Pagination组成的表格区
页面表格需要进行单行操作,于是有了由Drawer详情页BModal + BForm组成的弹框BModal + BConfirm组成的确认弹框

BFilter组件和BForm组件都是颗粒度比较小的组件,小到输入框、上传按钮、单选、多选、日期选择、下拉选择、级联选择…因此完全可以复用它们。


最后,问几个问题,这么搭ui库的意义?提升页面性能?或是其他目的?
按照这样写代码,究竟有哪些优势和劣势呢?
先说意义:
我认为这么搭最大的意义在于能快速生成统一交互、风格的页面
8个基础的弹框逻辑+20个基础的表单组件,根据业务配置不同的弹框逻辑+组件,后面按照这样的配置玩法,一天出10个这样的页面都不是事!

再来说下它的优势和劣势:
优势:
1.统一开发,新人直接按照这样的配置去写就行;
2.支持复用,不同项目可以共用这一套ui库;
3.快速生成页面。

劣势:
1.学习成本高,需系统地学习才能快速开发
由于文档的不即使更新、还有demo的不完善,想快速上手很难,得靠自己去理解。其次,如果不去看ui库内部的实现逻辑,你都不知道干了啥事情。

2.不可随antd一起升级UI库
由于ui库是在antd ui库基础上进行封装的,比如当时封装ui库时依赖antd4.0.0,随着时间的飞逝,antd升级到4.16.12后,难免会出现新特性及新api用不了的情况。
这时即使强升级antd到最新,也会带来很大的风险,毕竟很多之前的老特性没了。
之前在老项目里用到的老特性去实现的业务,可能就会出问题。
还有老项目里为了实现业务,做出的各种骚操作,在一升级后,也可能会出问题。

3.不能更改交互,交互一更改,开发效率直线下降
目前都是在一个页面弹各种框实现的各种业务,那如果新增、编辑、不是弹框,而是跳页面,又该如何实现呢?
目前的方法就两个:
一是挨去实现表单页面,重新开始绘制表单;(布局、样式可以自定义)
二是使用BForm去动态生成表单;(布局、样式自定义很难)


后面会写一篇文章,分析其ui库实现原理及具体怎么封装的,敬请期待。