React之表格行/列合并

时间:2022-11-20 11:05:06

 

参考链接:https://ant.design/components/table-cn/#components-table-demo-colspan-rowspan

参考图:

React之表格行/列合并

实现代码如下:

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);

 实际工作中通过参考该例子实现的效果如图:

React之表格行/列合并

实现代码如下:

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;避免重复合并导致错误。