企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持知识库和私有化部署方案 广告
在官网中有表格嵌套的案例:[https://ant.design/components/table-cn/#components-table-demo-nested-table](https://ant.design/components/table-cn/#components-table-demo-nested-table),而实际中子表的展开往往是通过异步请求来进行查看。 <br/> 首先子表的渲染是通过expandedRowRender处理,父表如下方所示。 ``` <Table columns={columns} size="small" className="components-table-demo-nested" expandedRowRender={expandedRowRender} dataSource={dataSource} bordered /> ``` <br/><br/> 刚开始我是根据官方示例所写,后来为了异步请求,我就把expandedRowRender函数表达式写成了声明函数,即expandedRowRender={this.expandedRowRender.bind(this} ,把异步请求写在里面。然后就发现一个问题,这样一写,expandedRowRender就像变成了一个定时器一样,一直在往后台发送请求,就没停下来过。不一会儿,你就能收到后端大哥的黑人问号脸。很明显,子表的渲染进入了一个死循环。 但是表格的嵌套又必须完成,终于,我发现了一个可以控制的方法:onExpand。于是expandedRowRender还是和官方那样写成函数表达式,父表进一步改成下方所示: ``` <Table columns={columns} size="small" className="components-table-demo-nested" expandedRowRender={expandedRowRender} onExpand={this.onExpand.bind(this)} dataSource={dataSource} bordered /> ``` 然后我们就可以在onExpand里面写异步请求了。示例如下: ``` onExpand(expanded, record) { if (!expanded) { return; } axios.post(url).then((res) => { let childData = res.data.data; if (childData !== null) { this.setState({ childData }) } }).catch((e) => { }); } ``` 展开子表,触发onExpand,请求到数据childData后,子表渲染expandedRowRender示例如下: ``` const expandedRowRender = () => { return <Table columns={childColums} size="small" dataSource={childData} pagination={false} />; }; ``` <br/><br/> 这个时候,表格嵌套就已经完成了。可是还是没那么简单,你会发现,打开第一行后,数据还是正常的,但是打开第二行后,第一行子表的数据居然也变成了第二行子表的数据了。很明显第一行子表的数据又被重新渲染了。如下图描述: ![](https://img.kancloud.cn/0f/f2/0ff2d7fe2b4c079d6adcbc55e5218658_814x592.png) 可是实际中两个子表的数据是不一样的,不能让这种Bug发生,然后我就想了个折中的办法:每次打开只能展开一个子表,如果展开另一个子表,那么其他子表都要关闭。这样,页面上只渲染了一个子表的数据,也避免子表展开过多影响查看。 查看了官网文档后,我发现了一个属性expandedRowKeys,官方描述这个是可以控制展开和收起的。然后我把父表进一步改成了下方所示: ``` <Table columns={columns} size="small" className="components-table-demo-nested" expandedRowRender={expandedRowRender} onExpand={this.onExpand.bind(this)} dataSource={dataSource} expandedRowKeys={this.state.expandedRowKeys} bordered /> ``` 注意它是通过一个数组来控制的,而且下标是从1开始。那么方法onExpand也要经过一下改造,对变量expandedRowKeys来进行控制: ``` onExpand(expanded, record) { if (!expanded) { // 关闭时把所有子表关上 this.setState({ expandedRowKeys: [] }); return; } // 打开时只打开当前数据,这里index是我手动往数据里面加的。就是父表数据请求过来的时候,循环一下加入一个index,下标从1开始。 this.setState({ expandedRowKeys: [record.index] }) axios.post(url).then((res) => { let childData = res.data.data; if (childData !== null) { this.setState({ childData }) } }).catch((e) => { }); } ``` <br/><br/> 好了,到了这一步,我天真的以为问题已经解决了,然而只是表面。当父表数据过多并加入翻页后,我又发现一个bug,那就是翻页后子表打不开!!!没关系,继续来解决。首先加入了翻页的父表如下所示: ``` <Table columns={columns} size="small" className="components-table-demo-nested" expandedRowRender={expandedRowRender} onExpand={this.onExpand.bind(this)} dataSource={dataSource} expandedRowKeys={this.state.expandedRowKeys} bordered onChange={this.pageChange.bind(this)} /> ``` 所以每次翻页都要把expandedRowKeys清空一下: ``` // 更改页数 pageChange(e) { this.setState({ current: e.current, pageSize: e.pageSize, expandedRowKeys: [], // 每次翻页把所有子表关闭 }, () => { this.updatePage(); // 请求数据请求更新页面 }) } ``` 在updatePage函数里,请求的是父表的数据,我们需要对下标index(关系子表展开的那个值)进行处理,而不是之前简单循环之后data.index = index + 1。利用页码current和每页数量pageSize,计算如下: ``` res.data.map((val,ind)=>{ val.index = this.state.pageSize * (this.state.current - 1) + (ind + 1); }) ``` 到此,真的是全部解决!!!