參考鏈接: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;避免重復合並導致錯誤。