el-table实现表头嵌套、表头单元格合并、内容区域单元格实现同值自动跨行

先看效果图:
在这里插入图片描述
最近要用Vue+ElementUI实现这种表格样式,因为也是第一次对el-table做这种处理,所以并不知晓是不是有更优的解决方案。把自己的代码放上来,欢迎大家提供更简单的实现方法哈。

PS:

红框内容:表头嵌套,通过el-table-column嵌套即可实现;

蓝框内容:左侧为表头跨列;右侧为表头跨行。(右侧效果:如果用el-table-column嵌套,会造成"考试结果"占一行,"成绩"占两行。)我的方案有些繁琐,先通过header-cell-class-name设置class名,然后在mounted里通过原生Js获取到dom节点,setAttribute实现;

黄框内容:凡是相邻的单元格,如果是同一所学校的话,就自动合并。最关键就是要获取到要合并的行数,详见代码。

<template>
<div class='tablePage'>
    <el-table 
        :data="tableData" 
        border 
        style="width: 100%"
        :header-cell-class-name="headerCrossRow"
        :span-method="moreRowsToOneRow"
    >
        <el-table-column header-align="center" label="辅导班学生汇总期末考试表">
            <el-table-column header-align="center" align="center" type="index" label="标识"></el-table-column>
            <el-table-column header-align="center" align="center" prop="studentNo" label="学号"></el-table-column>
            <el-table-column header-align="center" align="center" label="学生信息">
                <el-table-column header-align="center" align="center" prop="schoolName" label="所属学校"></el-table-column>
                <el-table-column header-align="center" label="基本信息">
                    <el-table-column header-align="center" align="center" prop="studentName" label="姓名"></el-table-column>
                    <el-table-column header-align="center" align="center" prop="studentAge" label="年龄"></el-table-column>
                </el-table-column>
            </el-table-column>
            <el-table-column header-align="center" label="考试结果">
                <el-table-column header-align="center" align="center">
                    <el-table-column header-align="center" align="center" prop="studentScore" label="成绩"></el-table-column>
                </el-table-column>
                <!-- <el-table-column header-align="center" align="center" prop="testLevel" label="等级"></el-table-column> -->
            </el-table-column>
        </el-table-column>
    </el-table>
</div>
</template>
<script>
let me;
  export default {
    data() {
      return {
        tableData: [
            {
                schoolName: 'A小学',
                studentNo: '2018001',
                studentName: 'Jack',
                studentScore: 92,
                testLevel: '优秀',
                studentAge: 17
            }, 
            {
                schoolName: 'A小学',
                studentNo: '2018002',
                studentName: 'Lily',
                studentScore: 99,
                testLevel: '优秀',
                studentAge: 16
            }, 
            {
                schoolName: 'A小学',
                studentNo: '2018003',
                studentName: 'Sony',
                studentScore: 58,
                testLevel: '不及格',
                studentAge: 18
            }, 
            {
                schoolName: 'B小学',
                studentNo: '2018004',
                studentName: 'Tom',
                studentScore: 74,
                testLevel: '良好',
                studentAge: 16
            },
            {
                schoolName: 'B小学',
                studentNo: '2018005',
                studentName: 'Jackie',
                studentScore: 92,
                testLevel: '优秀',
                studentAge: 16
            }, 
            {
                schoolName: 'B小学',
                studentNo: '2018006',
                studentName: 'Joe',
                studentScore: 99,
                testLevel: '优秀',
                studentAge: 16
            }, 
            {
                schoolName: 'B小学',
                studentNo: '2018007',
                studentName: 'Kobe',
                studentScore: 58,
                testLevel: '不及格',
                studentAge: 17
            }, 
            {
                schoolName: 'C小学',
                studentNo: '2018008',
                studentName: 'Tomcat',
                studentScore: 74,
                testLevel: '良好',
                studentAge: 17
            },
            {
                schoolName: 'B小学',
                studentNo: '2018009',
                studentName: 'Trump',
                studentScore: 92,
                testLevel: '优秀',
                studentAge: 18
            }, 
            {
                schoolName: 'C小学',
                studentNo: '2018010',
                studentName: 'Lily',
                studentScore: 49,
                testLevel: '不及格',
                studentAge: 17
            }, 
            {
                schoolName: 'C小学',
                studentNo: '2018011',
                studentName: 'Sony',
                studentScore: 58,
                testLevel: '不及格',
                studentAge: 17
            }, 
            {
                schoolName: 'C小学',
                studentNo: '2018012',
                studentName: 'Tom',
                studentScore: 74,
                testLevel: '良好',
                studentAge: 17
            },
            {
                schoolName: 'C小学',
                studentNo: '2018013',
                studentName: 'Jack',
                studentScore: 52,
                testLevel: '不及格',
                studentAge: 17
            }, 
            {
                schoolName: 'C小学',
                studentNo: '2018014',
                studentName: 'Lily',
                studentScore: 99,
                testLevel: '优秀',
                studentAge: 17
            }, 
        ]
      }
    },
    mounted(){
        me = this;
        var timer = setInterval(()=>{
            console.log('计时器10ms执行一次,一旦找到目标节点即停止')
            var setCrossRowDom1 = document.getElementsByClassName('setCrossRow1');
            var setCrossRowDom2 = document.getElementsByClassName('setCrossRow2');
            var setCrossColDom1 = document.getElementsByClassName('setCrossCol1');
            var setCrossColDom2 = document.getElementsByClassName('setCrossCol2');
            if(setCrossRowDom1.length > 0 && setCrossRowDom2.length > 0 && setCrossColDom1.length > 0 && setCrossColDom2.length > 0){
                setCrossRowDom1[0].setAttribute('rowspan', 2)
                setCrossRowDom2[0].setAttribute('style', 'display: none;')
                setCrossColDom1[0].setAttribute('colspan', 2)
                setCrossColDom2[0].setAttribute('style', 'display: none;')
                clearInterval(timer);
                timer = null;
            }
        }, 10)
    },
    methods: {
        // 一加载就给表头设置class,通过js设置表头里的单元格合并
        headerCrossRow({rowIndex, column}){
            if(rowIndex === 1 && column.label === '考试结果'){
                return 'setCrossRow1';
            } else if (rowIndex === 2 && !column.label) {
                return 'setCrossRow2';
            } else if (column.label === '标识') {
                return 'setCrossCol1';
            } else if (column.label === '学号') {
                return 'setCrossCol2';
            }
        },
        moreRowsToOneRow({ rowIndex, columnIndex }){
            // 学校是不同学生可能共同拥有的属性,所以需要合并。
            // 其他属性不应该合并,比如成绩,即使成绩相等,也不应该合并为同一个单元格
            if (columnIndex === 2) {
                // 遍历各行  看是要合并行、合并几行,还是隐藏
                // 比如第7行开始要合并3行,那么第8行和第9行就得隐藏,要不然会右移占用其他单元格
                for (var i of Array.from(me.tableData.keys())) {
                    if(rowIndex === i){
                        return me.heBingRowOfColumn2(i)//计算{colspan: X, rowspan: Y}的值
                    }
                }
            }
        },
        heBingRowOfColumn2(i){
            var itemList = me.tableData.map(item=>{
                return item.schoolName
            })
            // 先拿到学校列表,本示例中拿到的数组为:
            // ["A小学", "A小学", "A小学", "B小学", "B小学", "B小学", "B小学", "C小学", "B小学", "C小学", "C小学", "C小学", "C小学", "C小学"]
            // 第一行,没有上一行,所以要单独处理下
            var returnObj = null;
            if(i == 0){
                console.log(`${itemList[i]}从下标${i}开始出现了${countShowTimes(itemList, i)}次`)
                returnObj = { colspan: 1, rowspan: countShowTimes(itemList, i) }
            } else if (i >= 1) {// 第二行开始:
                if(itemList[i] == itemList[i-1]){// 如果和上面一行值相等,就隐藏
                    returnObj = { colspan: 0, rowspan: 0 }
                } else {// 如果和上面一行值不相等
                    console.log(`${itemList[i]}从第${i}开始出现了${countShowTimes(itemList, i)}次`)
                    returnObj = { colspan: 1, rowspan: countShowTimes(itemList, i) }
                }
            }
            return returnObj;//把合并的列数 行数返回给span-method的方法

            // 计算连续出现的次数,然后合并
            // 一旦有不同的值,则需要重新计数
            function countShowTimes (itemList, i) {
                var count = 1;
                // 如果一进来就是最后一个元素,那肯定只能出现一次,直接return
                if(i == (itemList.length-1)){
                    return 1;
                }
                for (var n=i+1;n<itemList.length;n++) {// 从i之后的那个元素开始遍历,一直到最后一个元素
                    if (itemList[n] === itemList[n-1]) {// 判断是否和前一个值相等,顺便处理一下边界值
                        count++;
                        if(n == (itemList.length-1)){//如果此时已经判断的是最后一个元素了,就可以return了
                            return count;
                        }
                    } else {// 如果出现不同的值了。或者如果到最后一个,再往后就没元素了,可以直接返回count了
                        return count;
                    }
                }
            }
        },
    },
  }
</script>
<style lang="scss" scoped>
.tablePage {
    width: 100vw;
    height: 100vh;
    overflow: auto;
}
</style>
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值