table表格支持这种树形可展开的形式,只需要在tableData中有children数据
不过这种用法是一开始获取表格数据时,就把children数据拿到了
实际场景中可能需要点击展开按钮时再去调取children数据
可以有两种方法实现这个需求
第一种: 通过expandable的onExpand方法,点击展开时获取数据,再通过筛选过滤,将数据添加到父级数据的children中
这里使用的是protable,antd table组件用法也是一样的.不过因为是通过改变tableData的数据,所以不要用request的方法赋值tableData
数据要求: 父级数据中需要一个字段表示当前的层级, 如果不是顶层数据,还要有一个字段表示父级id,方便添加数据时匹配
这里层级最多三级, 直接写了,如果不确定有几层的,需要写递归
import React, { useState, useEffect } from 'react';
import ProTable from '@ant-design/pro-table';
import { getCityList, getAreaList, getProvinces } from '@/services/citylist';
import { isEmpty } from 'lodash';
const TreeTable: React.FC = () => {
const [tableData2, setTableData2] = useState<any[]>([]);
const colums: any[] = [
{
title: '省份',
dataIndex: 'province',
width: '20%',
render: (val: string, recored: any) => {
if (recored.city) return '-';
return val;
},
},
{
title: '市区',
dataIndex: 'city',
width: '20%',
render: (val: string, recored: any) => {
if (recored.area) return '-';
return val;
},
},
{
title: '区县',
width: '20%',
dataIndex: 'area',
},
{
title: 'GDP(亿)',
width: '19%',
dataIndex: 'gdp',
valueType: 'digit',
},
{
title: '排名',
width: '18%',
dataIndex: 'rank',
},
];
// 获取树形数据
const getData2 = async () => {
const res: any = await getProvinces();
setTableData2(res);
};
useEffect(() => {
getData2();
}, []);
// 点击展开
const areaExpandedRowsChange = async (expanded: boolean, record: any) => {
console.log(expanded, record);
// 做一下限制,如果已经有数据,不再重复请求数据
if (expanded && record.children && isEmpty(record.children)) {
if (record.level === 1) { // 获取第一级数据的children
const res = await getCityList(record.province, 1);
setTableData2(
tableData2.map((item: any) => {
if (item.id === record.id) {
return {
...item,
children: res,
};
}
return item;
}),
);
} else if (record.level === 2) { // 获取第二级数据的children
const res = await getAreaList(record);
setTableData2(
tableData2.map((item: any) => {
const obj = {
...item,
};
if (item.id === record.parentId) {
item.children.forEach((ss: any) => {
if (ss.id === record.id) {
ss.children = res;
}
});
}
return obj;
}),
);
}
}
};
return (
<ProTable
bordered
columns={colums}
rowKey="id"
search={false}
dataSource={tableData2}
expandable={{
onExpand: areaExpandedRowsChange,
}}
pagination={false}
toolBarRender={false}
/>
)
}
export default TreeTable;
这种方法在添加数据时,麻烦一点,但是展示和交互比较友好.适合层级确定,并且层级数比较少的情况
第二种方法: 通过expandable的expandedRowRender属性,返回自定义内容
这种可以方便的定义要展示的children数据,因为返回的是DOM,
这种层级可以嵌套,但是有几层数据必须确定
import React, { useState, useEffect } from 'react';
import ProTable from '@ant-design/pro-table';
import { getCityList, getAreaList, getProvinces } from '@/services/citylist';
import { isEmpty } from 'lodash';
const TreeTable: React.FC = () => {
const [tableData2, setTableData2] = useState<any[]>([]);
const colums: any[] = [
{
title: '省份',
dataIndex: 'province',
width: '20%',
render: (val: string, recored: any) => {
if (recored.city) return '-';
return val;
},
},
{
title: '市区',
dataIndex: 'city',
width: '20%',
render: (val: string, recored: any) => {
if (recored.area) return '-';
return val;
},
},
{
title: '区县',
width: '20%',
dataIndex: 'area',
},
{
title: 'GDP(亿)',
width: '19%',
dataIndex: 'gdp',
valueType: 'digit',
},
{
title: '排名',
width: '18%',
dataIndex: 'rank',
},
];
const colums2 = [
{
title: '',
dataIndex: 'gdp',
width: 45,
render: () => '',
},
...colums,
];
// 获取表格数据
const getData = () => {
setTableData([
{
id: 1,
province: '广东省',
city: '',
area: '',
gdp: 7999,
},
{
id: 2,
province: '浙江省',
city: '',
area: '',
gdp: 6990,
},
{
id: 3,
province: '江苏省',
city: '',
area: '',
gdp: 5990,
},
{
id: 4,
province: '北京市',
city: '',
area: '',
gdp: 8990,
},
{
id: 5,
province: '上海市',
city: '',
area: '',
gdp: 8999,
},
]);
};
useEffect(() => {
getData();
}, []);
// 市渲染
const provinceRender = (record: any) => {
// 如果表格数据没变化,不会重新调接口,这里不需要再判断是否有值
// 获取城市数据
const getCitys = async () => {
const res = await getCityList(record.province);
return {
data: res,
};
};
// 区渲染
const cityRender = (row: any) => {
// 获取区数据
const getAreas = async () => {
const res = await getAreaList(row);
return {
data: res,
};
};
return (
<ProTable
bordered
columns={colums2}
rowKey="id"
search={false}
request={getAreas}
pagination={false}
toolBarRender={false}
showHeader={false}
/>
);
};
return ( // 渲染的数据可以自定义
<ProTable
bordered
columns={colums}
rowKey="id"
search={false}
request={getCitys}
expandable={{
expandedRowRender: cityRender,
// expandedRowKeys: cityRowKeys,
// onExpandedRowsChange: cityExpandedRowsChange
}}
pagination={false}
toolBarRender={false}
showHeader={false}
/>
);
};
return (
<ProTable
bordered
columns={colums}
rowKey="id"
search={false}
dataSource={tableData}
expandable={{
expandedRowRender: provinceRender,
// expandedRowKeys: provinceRowKeys, // 如果需要筛选, 每次调用接口时将展开项收起,需要将expandedRowKeys属性设为可控,
// onExpandedRowsChange: provinceExpandedRowsChange
}}
pagination={false}
toolBarRender={false}
/>
)
}
export default TreeTable;
这种方法不需要处理原始表格数据, 缺点是交互样式差一点, 展开按钮都在最左侧, 不能通过是否有下一级来区别展示展开图标
总结: 这两种方式都可以异步获取子级数据,具体用那种可以根据实际应用场景选择
antd table的文档说明
源代码: https://github.com/shengbid/antdpro-demo/tree/main/src/pages/Table/treeTable