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的文檔說明
