参考链接:https://ant.design/components/table-cn/#components-table-demo-colspan-rowspan
参考图:
实现代码如下:
import { Table } from 'antd'; // In the fifth row, other columns are merged into first column // by setting it's colSpan to be 0 const renderContent = (value, row, index) => { const obj = { children: value, props: {}, }; if (index === 4) { obj.props.colSpan = 0; } return obj; }; const columns = [{ title: 'Name', dataIndex: 'name', render: (text, row, index) => { if (index < 4) { return <a href="javascript:;">{text}</a>; } return { children: <a href="javascript:;">{text}</a>, props: { colSpan: 5, }, }; }, }, { title: 'Age', dataIndex: 'age', render: renderContent, }, { title: 'Home phone', colSpan: 2, dataIndex: 'tel', render: (value, row, index) => { const obj = { children: value, props: {}, }; if (index === 2) { obj.props.rowSpan = 2; } // These two are merged into above cell if (index === 3) { obj.props.rowSpan = 0; } if (index === 4) { obj.props.colSpan = 0; } return obj; }, }, { title: 'Phone', colSpan: 0, dataIndex: 'phone', render: renderContent, }, { title: 'Address', dataIndex: 'address', render: renderContent, }]; const data = [{ key: '1', name: 'John Brown', age: 32, tel: '0571-22098909', phone: 18889898989, address: 'New York No. 1 Lake Park', }, { key: '2', name: 'Jim Green', tel: '0571-22098333', phone: 18889898888, age: 42, address: 'London No. 1 Lake Park', }, { key: '3', name: 'Joe Black', age: 32, tel: '0575-22098909', phone: 18900010002, address: 'Sidney No. 1 Lake Park', }, { key: '4', name: 'Jim Red', age: 18, tel: '0575-22098909', phone: 18900010002, address: 'London No. 2 Lake Park', }, { key: '5', name: 'Jake White', age: 18, tel: '0575-22098909', phone: 18900010002, address: 'Dublin No. 2 Lake Park', }]; ReactDOM.render(<Table columns={columns} dataSource={data} bordered />, mountNode);
实际工作中通过参考该例子实现的效果如图:
实现代码如下:
import React from 'react';
import {Table} from 'antd';
import { queryCreditsAndPeriods } from './service';
export default class TotalCreditsAndHoursModal extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
total: 0,
dataSource: []
};
}
params = {
pageNo: 1,
pageSize: 10,
}
componentWillMount() {
this.queryCreditsAndPeriods();
}
// 根据majorId(年级专业方向ID)查询专业方案下的总毕业学分及学时
queryCreditsAndPeriods = () => {
queryCreditsAndPeriods(this.props.majorId, (response) => {
this.setState({
dataSource: response
});
})
}
// 获取tablebox的ref
onTableBoxRef = ref => {
this.tableBoxRef = ref;
};
render() {
const {dataSource} = this.state;
// 模块名称合并计算
let numObj = {};
dataSource.map((elem) => {
let moduleName = elem.schemeModuleName;
if (moduleName in numObj) {
numObj[moduleName] += 1
} else {
numObj[moduleName] = 1
}
})
// 隶属类别合并计算
let numObj3 = {};
dataSource.map((elem,index) => {
let classifyParentName= elem.schemeClassifyParentName;
if (classifyParentName in numObj3 ) {
numObj3[classifyParentName] += 1
} else {
if(typeof(classifyParentName) === "undefined"){
numObj3["undefined"+index] = 1
}else{
numObj3[classifyParentName] = 1
}
}
})
// 小数点转百分号的处理函数
const renderContent = (value) => {
if (value != undefined && value != null) {
// 转为百分比展示
const scale = Math.round((value * 10000) / 100.00) + '%';
return scale;
}
};
let mergeObj = []; // 合并所属类别
const columns = [
{
title: '方案模块',
align: 'center',
dataIndex: 'schemeModuleName',
key: 'schemeModuleName',
width: '20%',
render: (value, row, index) => {
const obj = {
children: <span style={{fontWeight: 'bold'}}>{value}</span>,
props: {}
};
if (index === dataSource.length-1) {
obj.props.colSpan = 3;
obj.props.rowSpan = 1;
}
if ((index > 0 && value !== dataSource[index - 1].schemeModuleName) || index == 0) {
obj.props.rowSpan = numObj[value]
} else {
obj.props.rowSpan = 0;
}
return obj;
}
},
{
title: '隶属类别',
align: 'center',
colSpan: 0,
width: '10%',
dataIndex: 'schemeClassifyParentName',
key: 'schemeClassifyParentName',
render: (value, row, index) => {
const obj = {
children: value,
props: {},
};
// 只要没有隶属类别这一列,则设置colSpan为0
if (typeof(value) === 'undefined') {
obj.props.colSpan = 0;
// 判断是否是第一个出现,如果是则设置合并指定的行,已出现过同一个的值就不要合并行了,则设置rowSpan为0
} else if (mergeObj.indexOf(value) == -1 ){
obj.props.rowSpan = numObj3[value];
mergeObj.push(value);
}else {
obj.props.rowSpan = 0;
}
// 判断如果是最后一行,则设置rowSpan为0,表格不会渲染
if (index === dataSource.length-1) {
obj.props.colSpan = 0;
}
return obj;
},
},
{
title: '方案类别',
align: 'center',
colSpan: 2,
width: '20%',
dataIndex: 'schemeClassifyName',
key: 'schemeClassifyName',
render: (value, row, index) => {
const obj = {
children: value,
props: {},
};
// 判断所属类别那行的值是否存在,如果不存在则直接设置合并2列
if (typeof(dataSource[index].schemeClassifyParentName) === "undefined" ) {
obj.props.colSpan = 2;
}
// 判断如果是最后一行,则设置rowSpan为0,表格不会渲染
if (index === dataSource.length-1) {
obj.props.colSpan = 0;
}
return obj;
},
},
{
title: '总学分',
align: 'center',
width: '10%',
dataIndex: 'schemeSystemCredit',
key: 'schemeSystemCredit',
},
{
title: '学分比例',
align: 'center',
width: '15%',
dataIndex: 'creditScale',
key: 'creditScale',
render: renderContent,
},
{
title: '总学时',
align: 'center',
width: '10%',
dataIndex: 'schemeSystemPeriod',
key: 'schemeSystemPeriod',
},
{
title: '学时比例',
align: 'center',
width: '15%',
dataIndex: 'periodScale',
key: 'periodScale',
render: renderContent,
}
];
return (
<div style={{marginRight:'10px',marginLeft:'20px'}}>
<Table height={272} columns={columns} dataSource={this.state.dataSource} bordered />
</div>
);
}
}
总结:不管是合并行还是合并列,只跟要操作的列有关,与表格中的其他列都没有关系,在处理过程中,主要处理思路是对要合并的列展开。
比如我上图是想要合并方案模块,所属方案类别,方案类别这三列进行合并行/列。
其中
if ((index > 0 && value !== dataSource[index - 1].schemeModuleName) || index == 0) { obj.props.rowSpan = numObj[value] } else { obj.props.rowSpan = 0; }
这里要求的数据格式相同的方案模块放在一起,这样便于判断以及设置合并行数或者列数。这个思想很重要:比如有两条数据:[{parent:'主干课',children:'科学课'},{parant:'主干课',children:'自然课'}] 解读:第一次遍历数据时,通过index == 0 进入obj.props.rowSpan = numObj[value]这个循环内
,第二次,再次判断第一次的值(parent)是否跟第二次的值(parent)相等,如果相等,则设置为obj.props.rowSpan = 0;避免重复合并导致错误。