写在前面:
在这篇文章中,你会了解到:
1.为什么需要ProTable?
antd pro 中的大部分组件来自于 antd , 而 antd pro table 则是基于 antd 的 table 组件再封装了一层, 熟练使用 antd pro table, 能够覆盖大部分增删改查业务的需要, 关键是只需要极少的配置, 就能得到一个完善的表格。引用官方的话来说,那就是
antd 作为服务于企业级产品的设计体系的组件库,已经提供了强大的 Table,但是业务的不同导致我们仍有需要进行一些定制,不同的单元格有很多不同的数据格式,金额,日期,数字等,包括一些常用的操作,页码切换时的重新请求,刷新数据等,这些都是很简单的重复劳动,但是却不可避免。
ProTable 就是为了解决这些问题,在 Table 的层面上提供了一些预设,你可以通过 valueType 来支持各种类型的数据,预设了金额,日期,序号,进度条 等多种类型,并且支持通过 valueEnum 来映射枚举,解决非常烦人的各种枚举配置,可以大大的简化代码。
综上,一言以蔽之,ProTable is fucking awesome!(But还是有一些小问题需要解决。)
2.ProTable的主要板块
在大部分场景中,我们只需要配置这四种颜色的板块即可:
已经选择项
),tableAlertRender(当前共选中 1 项,共有 1 项未解决
),tableAlertOptionRender(自定义 清空
)三个属性进行配置<ProTable
columns={columns}
request={async (params = {}) => //请求数据
request('https://proapi.azurewebsites.net/github/issues', {
params,
})
}
rowKey="id"
rowSelection={{}}
tableAlertRender={({ selectedRowKeys, selectedRows }) =>
`当前共选中 ${selectedRowKeys.length} 项,共有 ${selectedRows.reduce((pre, item) => {
if (item.state === 'open') {
return pre + 1;
}
console.log(selectedRowKeys,selectedRows)
return pre;
}, 0)} 项未解决 `
}
tableAlertOptionRender={props => {
const { onCleanSelected } = props;
return (
<Space>
<a>自定义</a>
<a onClick={onCleanSelected}>清空</a>
</Space>
);
}}
dateFormatter="string"
headerTitle="批量操作"
toolBarRender={(_, { selectedRowKeys }) => [ //配置绿色框中的内容
<Button key="3" type="primary">
<PlusOutlined />
新建
</Button>,
selectedRowKeys && selectedRowKeys.length && (
<Button
key="3"
onClick={() => {
window.alert(selectedRowKeys.join('-'));
}}
>
批量删除
</Button>
),
]}
/>
1.cloumns
以下笔者把一些需要尝试才能试出来的属性标注,其余一看文档就懂的属性,笔者就不赘述了
const columns = [
{
title: '序号', // 对应表头的文字
dataIndex: 'index', //对应你的字段名称
valueType: 'indexBorder', //indexBorder就是proTable自动帮你生成的1,2,3,4的序号
width: 72, //通过width属性, 可以自行调节这一栏的宽度,不过总宽度不要超过100%哦
},
{
title: '标题',
dataIndex: 'title',
copyable: true, //多出来一个蓝色的复制icon,点击就直接进行复制
ellipsis: true, //用...代替没有显示的文本,并且在鼠标移到相应的文本上会显示全部的相应文本
tip: '标题过长会自动收缩', //显示在表头作为一个提示
width: '30%',
hideInSearch: true, //在最上面的搜索栏不显示该字段
},
{
title: '状态',
dataIndex: 'state',
initialValue: 'all',
filters: true,
valueEnum: {
all: { //key表示选中该状态后,所获得的值
text: '全部', //text表示实际显示出来的文本
status: 'Default', //表示文字前面的那一个点是什么颜色
},
open: {
text: '未解决',
status: 'Error', //表示文字前面的那一个点是什么颜色 :红色
},
closed: {
text: '已解决',
status: 'Success', //表示文字前面的那一个点是什么颜色 :绿色
},
processing: {
text: '解决中',
status: 'Processing',
},
},
width: '10%',
},
{
title: '标签',
dataIndex: 'labels',
width: '10%',
render: (_, row) => ( //自定义渲染方法,返回一个ReactNode,row就是这一整行的数据
<Space>
{row.labels.map(({ name, id, color }) => (
<Tag color={color} key={id}>
{name}
</Tag>
))}
</Space>
),
},
{
title: '创建时间',
key: 'since',
dataIndex: 'created_at',
valueType: 'dateTime',
width: '20%',
},
{
title: '操作',
valueType: 'option',
render: (text, row, _, action) => [
//自定义渲染方法,返回一个ReactNode,row就是这一整行的数据
<a href={row.html_url} target="_blank" rel="noopener noreferrer" key="link">
链路
</a>,
<a href={row.html_url} target="_blank" rel="noopener noreferrer" key="warning">
报警
</a>,
<a href={row.html_url} target="_blank" rel="noopener noreferrer" key="view">
查看
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action.reload()}
// action 是Form.useForm暴露出来的对象,便于手动触发表格操作
menus={[
{
key: 'copy',
name: '复制',
},
{
key: 'delete',
name: '删除',
},
]}
/>,
],
},
];
2.数据加载:跳过models,直接使用service进行API管理
首先是页面初始化的时候,通过request属性加载相应的数据,request属性,携带当前页数(current)和页面数据量(pageSize)两个变量,但是在改变当前页数,都会再次触发request发起请求。
index.jsx
import {getData,changeData} from './service'
....省略
<ProTable
...省略
request = {async (params)=>{
let data = Object.assign(params,...把其它需要的参数,绑定到params)
let res = await getData(data)
return {
data:data ,
success:true
total:data.total
}
}}
/>
service.js
小tips,request中,如果key为params会将参数拼接在地址后面,而data,则是会将参数放在请求体中,并且PUT,DELETE方法也是使用data属性
import request from '@/utils/request'
export async function getData(params){
return request('/api/test',{
params:params
})
}
export async function changeData(params){
return request('/api/test',{
data:params,
methods:"POST"
})
}
返回数据格式的坑:
大家要注意的一点是,request属性对于返回的数据格式是有要求的
request={async (params = {}) =>
{
console.log("params",params)
return {
data: dataSource,
total: tableListDataSource.length,
success: true,
pageSize,
current: parseInt(`${params.currentPage}`, 10) || 1,
}
}
}
特别是前三个data,total,success字段,如果没有的话,页面是没有数据的,刚开始用pro的时候,笔者在这里踩过坑, 标注一下!
ps:
如果用户在进入页面的时候不需要自动触发request请求数据,需要用户手动查询之后,才会获取到数据,只需要添加一个。manualRequest = {true}属性即可,但注意,添加这个属性之后,最上方的serach就是不可隐藏的了。
3.数据更新,调用action
/**
* 添加节点
* @param fields
*/
const handleAdd = async fields => { //添加数据
const hide = message.loading('正在添加');
try {
await addRule({ ...fields }); //调用相应的service中的api即可
hide();
message.success('添加成功');
actionRef.current.reload() //刷新表格,触发request属性拉取最新数据
} catch (error) {
hide();
message.error('添加失败请重试!');
}
};
其它action操作
// 刷新
ref.current.reload();
// 加载更多
ref.current.fetchMore();
// 重置到默认值
ref.current.reset();
// 清空选中项
ref.current.clearSelected();
ps
:这里只是对于是否成功发起请求进行了判断,但是如果要进行错误处理的话,目前根据umi-request官方的说法,最多只能在model中的effect或者reducer中进行处理,无法直接在umi-request使用中间件或者用其它方法在源头处理,umi-request即使请求失败,依旧会把失败的相应返回给用户。
4.疑问:将model与ProTable结合
这是问题示范,笔者还没有实践成果过,大家注意
(1)写service
import request from '@/utils/request'
export async function getData(params){
return request('https://proapi.azurewebsites.net/github/issues',{
params:params
}) //此处笔者直接使用官方提供的api作为测试api
}
(2)写model
import {getData,changeData} from './service'
const TestModel = {
namespace:"TestModel",
state:{
testData:[]
},
effects:{
*fetchTestData({payload},{put,call}){
const response = yield call(getData,payload) //调用api
yield put({ //触发saveData这个reducer
type:"saveData",
payload:response
})
}
},
reducers:{
saveData(state,action){
return {...state,testData:action.payload || {}} //将获取到的数据合并到state中
}
}
}
export default TestModel
(3)将dispatch和state连接到组件上
import {connect} from 'dva'
export default connect(({TestModel})=>({ //TestModel是相应的namespace
testData:TestModel.testData
}))(Test)
(4)将dispatch写入request属性中,并且将testData赋给dataSource属性(用来初始化table)
<ProTable
。。。省略
request = {(params)=>{
dispatch({
type:"TestModel/fetchTestData",
payload:params
})
}}
dataSource={testData}
/>
这样即使数据格式正确,pro仍然无法正确显示数据,一脸懵逼。。。。
以上就是关于Protable的全部内容
详情请查阅官方文档:ProComponents
感谢阅读,欢迎批评指正,希望大家能够在追求卓越中不断进步,让优秀成为一种习惯~