应用系统定制开发el-table表格动态合并行、合并行列及详解

📝 个人简介

⭐ 个人主页:🙋‍
🍊 博客领域:编程基础、前端💻
🍅 写作风格:干货!干货!都是干货!
🍑 精选专栏:
🛸 支持段段:点赞👍、收藏⭐、留言💬

文章目录

前言

应用系统定制开发在写项目的时候有时候应用系统定制开发会经常遇到把行和列合应用系统定制开发并起来的情况,应用系统定制开发因为有些数据是重复渲染的,应用系统定制开发不合并行列会使表格看应用系统定制开发起来非常的混乱,如下:

应用系统定制开发而我们想要的数据是下应用系统定制开发面这种情况,应用系统定制开发将重复的行进行合并,应用系统定制开发使表格看起来简单明了,如下:

1、合并行

应用系统定制开发所谓的合并行就是将多行相同的数据变成一行来显示,直接上代码,页面的布局比较简单

<template>    <div class="table">        <el-table :data="tableData" :span-method="objectSpanMethod" border style="width: 100%">            <el-table-column prop="time" label="时间"></el-table-column>            <el-table-column prop="grade" label="年级"></el-table-column>            <el-table-column prop="name" label="姓名"></el-table-column>            <el-table-column prop="subjects" label="科目"></el-table-column>            <el-table-column prop="score" label="成绩"></el-table-column>        </el-table>    </div></template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

span-method是上属性,其值是一个函数,objectSpanMethod方法是用来处理合并行的返回值,tableData数据如下:

tableData: [    { time: '2020-08-10', grade: '三年二班', name: '小明', subjects: '语文', score: 80 },    { time: '2020-08-10', grade: '三年二班', name: '小明', subjects: '数学', score: 80 },     { time: '2020-08-10', grade: '三年一班', name: '小雷', subjects: '语文', score: 70 },    { time: '2020-08-10', grade: '三年一班', name: '小雷', subjects: '数学', score: 80 },    { time: '2020-08-11', grade: '三年三班', name: '小花', subjects: '语文', score: 60 },     { time: '2020-08-11', grade: '三年三班', name: '小花', subjects: '数学', score: 60 }, ],mergeObj: {}, // 用来记录需要合并行的下标mergeArr: ['time', 'grade', 'name', 'subjects', 'score'] // 表格中的列名
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

首先需要对数据就行处理,就是比较当前行与上一行的值是否相等(如果是第一行数据,直接将值赋值为1)

mounted中调用数据初始化数据的方法,如下:

mounted() {    this.getSpanArr(this.tableData);}
  • 1
  • 2
  • 3
// getSpanArr方法getSpanArr(data) {    this.mergeArr.forEach((key, index1) => {        let count = 0; // 用来记录需要合并行的起始位置        this.mergeObj[key] = []; // 记录每一列的合并信息        data.forEach((item, index) => {            // index == 0表示数据为第一行,直接 push 一个 1            if(index === 0) {                this.mergeObj[key].push(1);             } else {                // 判断当前行是否与上一行其值相等 如果相等 在 count 记录的位置其值 +1 表示当前行需要合并 并push 一个 0 作为占位                if(item[key] === data[index - 1][key]) {                     this.mergeObj[key][count] += 1;                    this.mergeObj[key].push(0);                } else {                    // 如果当前行和上一行其值不相等                     count = index; // 记录当前位置                     this.mergeObj[key].push(1); // 重新push 一个 1                }            }        })    })}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

数据处理好之后就可以调用objectSpanMethod方法了,如下:

// objectSpanMethod方法// 默认接受四个值 { 当前行的值, 当前列的值, 行的下标, 列的下标 }objectSpanMethod({ row, column, rowIndex, columnIndex }) {    // 判断列的属性    if(this.mergeArr.indexOf(column.property) !== -1) {         // 判断其值是不是为0         if(this.mergeObj[column.property][rowIndex]) {             return [this.mergeObj[column.property][rowIndex], 1]        } else {            // 如果为0则为需要合并的行            return [0, 0];         }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

合并后的结果就是我们想要的形式:

合并行完整的代码如下:

<template>    <div class="table">        <el-table :data="tableData" :span-method="objectSpanMethod" border style="width: 100%">            <el-table-column prop="time" label="时间"></el-table-column>            <el-table-column prop="grade" label="年级"></el-table-column>            <el-table-column prop="name" label="姓名"></el-table-column>            <el-table-column prop="subjects" label="科目"></el-table-column>            <el-table-column prop="score" label="成绩"></el-table-column>        </el-table>    </div></template><script>export default {    name: 'Table',    data() {        return {            tableData: [                { time: '2020-08-10', grade: '三年二班', name: '小明', subjects: '语文', score: 80 },                { time: '2020-08-10', grade: '三年二班', name: '小明', subjects: '数学', score: 80 },                { time: '2020-08-10', grade: '三年一班', name: '小雷', subjects: '语文', score: 70 },                { time: '2020-08-10', grade: '三年一班', name: '小雷', subjects: '数学', score: 80 },                { time: '2020-08-11', grade: '三年三班', name: '小花', subjects: '语文', score: 60 },                 { time: '2020-08-11', grade: '三年三班', name: '小花', subjects: '数学', score: 60 },             ],            mergeObj: {},            mergeArr: ['time', 'grade', 'name', 'subjects', 'score'],        };    },    methods: {        getSpanArr(data) {            this.mergeArr.forEach((key, index1) => {                let count = 0; // 用来记录需要合并行的起始位置                this.mergeObj[key] = []; // 记录每一列的合并信息                data.forEach((item, index) => {                    // index == 0表示数据为第一行,直接 push 一个 1                    if(index === 0) {                        this.mergeObj[key].push(1);                     } else {                        // 判断当前行是否与上一行其值相等 如果相等 在 count 记录的位置其值 +1 表示当前行需要合并 并push 一个 0 作为占位                        if(item[key] === data[index - 1][key]) {                             this.mergeObj[key][count] += 1;                            this.mergeObj[key].push(0);                        } else {                            // 如果当前行和上一行其值不相等                             count = index; // 记录当前位置                             this.mergeObj[key].push(1); // 重新push 一个 1                        }                    }                })            })        },        // 默认接受四个值 { 当前行的值, 当前列的值, 行的下标, 列的下标 }        objectSpanMethod({ row, column, rowIndex, columnIndex }) {            // 判断列的属性            if(this.mergeArr.indexOf(column.property) !== -1) {                 // 判断其值是不是为0                 if(this.mergeObj[column.property][rowIndex]) {                     return [this.mergeObj[column.property][rowIndex], 1]                } else {                    // 如果为0则为需要合并的行                    return [0, 0];                 }            }        }    },    mounted() {        this.getSpanArr(this.tableData);    }};</script><style lang="stylus" scoped>.table     height 100vh    width 100%    padding 40px    box-sizing border-box    /deep/ .el-table__body tr:hover > td        background-color: #fff;</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82

2、合并行列

调整下数据,如下:

tableData: [    { time: '2020-08-10', grade: '三年二班', name: '小明', subjects: '语文', score: 80 },    { time: '2020-08-10', grade: '三年二班', name: '小明', subjects: '数学', score: 80 },     { time: '2020-08-10', grade: '总成绩', name: '总成绩', subjects: '总成绩', score: 160 },    { time: '2020-08-10', grade: '三年一班', name: '小雷', subjects: '语文', score: 70 },    { time: '2020-08-10', grade: '三年一班', name: '小雷', subjects: '数学', score: 80 },    { time: '2020-08-10', grade: '总成绩', name: '总成绩', subjects: '总成绩', score: 150 },     { time: '2020-08-11', grade: '三年三班', name: '小花', subjects: '语文', score: 60 },     { time: '2020-08-11', grade: '三年三班', name: '小花', subjects: '数学', score: 60 },     { time: '2020-08-11', grade: '总成绩', name: '总成绩', subjects: '总成绩', score: 120 }],
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

可以看到上面的数据多了一行总成绩,现在的数据在页面显示效果如下:

可以看到总成绩的三个列并没有合并,并不是我们想要的效果,所以需要换一种思路来处理数据

页面的布局也有所调整,如下:

<template>    <div class="table">        <el-table :data="tableData" :span-method="objectSpanMethods" border style="width: 100%">            <template v-for="cols in colConfigs">                <!-- 无需合并的列 -->                <el-table-column                    v-if="cols.type === 'label' && !cols.children"                    :key="cols.prop"                    :prop="cols.prop"                    :label="cols.label"                >                </el-table-column>                <!-- 需要合并的列 -->                <template v-else-if="cols.type === 'label' && cols.children">                    <el-table-column                        v-for="children in cols.children"                        :key="children.prop"                        :prop="children.prop"                        :label="children.label"                    />                </template>            </template>        </el-table>    </div></template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

tableData中的数据就是上面调整后的,还需要声明的变量如下:

// 表格的信息 需要合并的需要放在 children 中colConfigs: [    {        type: 'label',        children: [            { prop: 'time', label: '时间' },            { prop: 'grade', label: '年级' },            { prop: 'name', label: '姓名' },            { prop: 'subjects', label: '科目' },            { prop: 'score', label: '成绩' }        ]    }],// 需要合并的行列信息mergeCols: [    { index: 0, name: 'time' },    { index: 1, name: 'grade' },    { index: 2, name: 'name' },    { index: 3, name: 'subjects' },    { index: 4, name: 'score' },],// 用来记录每一个单元格的下标tableMergeIndex: [],
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

首先也需要处理数据,在mounted中调用数据初始化数据的方法,如下:

mounted() {    if(this.mergeCols.length > 0) {        this.newTableMergeData();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
// newTableMergeData方法newTableMergeData() {    for (let i = 0; i < this.tableData.length; i++) {        for (let j = 0; j < this.mergeCols.length; j++) {            // 初始化行、列坐标信息            let rowIndex = 1;            let columnIndex = 1;            // 比较横坐标左方的第一个元素            if (j > 0 && this.tableData[i][this.mergeCols[j]['name']] === this.tableData[i][this.mergeCols[j - 1]['name']]) {                columnIndex = 0;            }            // 比较纵坐标上方的第一个元素            if (i > 0 && this.tableData[i][this.mergeCols[j]['name']] === this.tableData[i - 1][this.mergeCols[j]['name']]) {                rowIndex = 0;            }            // 比较横坐标右方元素            if (columnIndex > 0) {                columnIndex = this.onColIndex(this.tableData[i], j, j + 1, 1, this.mergeCols.length);            }            // 比较纵坐标下方元素            if (rowIndex > 0) {                rowIndex = this.onRowIndex(this.tableData, i, i + 1, 1, this.mergeCols[j]['name']);            }            let key = this.mergeCols[j]['index'] + '_' + i;            this.tableMergeIndex[key] = [rowIndex, columnIndex];        }    }},/**  * 计算列坐标信息  * data 单元格所在行数据  * index 当前下标  * nextIndex 下一个元素坐标  * count 相同内容的数量  * maxLength 当前行的列总数  */onColIndex(data, index, nextIndex, count, maxLength) {    // 比较当前单元格中的数据与同一行之后的单元格是否相同    if (nextIndex < maxLength && data[this.mergeCols[index]['name']] === data[this.mergeCols[nextIndex]['name']]) {        return this.onColIndex(data, index, ++nextIndex, ++count, maxLength);    }    return count;},/**  * 计算行坐标信息  * data 表格总数据  * index 当前下标  * nextIndex 下一个元素坐标  * count 相同内容的数量  * name 数据的key  */onRowIndex(data, index, nextIndex, count, name) {    // 比较当前单元格中的数据与同一列之后的单元格是否相同    if (nextIndex < data.length && data[index][name] === data[nextIndex][name]) {        return this.onRowIndex(data, index, ++nextIndex, ++count, name);    }    return count;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

数据处理好之后就可以调用objectSpanMethods方法了,如下:

objectSpanMethods({ row, column, rowIndex, columnIndex }) {    let key = columnIndex + '_' + rowIndex;    if (this.tableMergeIndex[key]) {        return this.tableMergeIndex[key];    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

实现的效果图如下:


合并行列的完整代码如下:

<template>    <div class="table">        <el-table :data="tableData" :span-method="objectSpanMethods" border style="width: 100%">            <template v-for="cols in colConfigs">                <!-- 无需合并的列 -->                <el-table-column                    v-if="cols.type === 'label' && !cols.children"                    :key="cols.prop"                    :prop="cols.prop"                    :label="cols.label"                >                </el-table-column>                <!-- 需要合并的列 -->                <template v-else-if="cols.type === 'label' && cols.children">                    <el-table-column                        v-for="children in cols.children"                        :key="children.prop"                        :prop="children.prop"                        :label="children.label"                    />                </template>            </template>        </el-table>    </div></template><script>export default {    name: 'Table',    data() {        return {            tableData: [                { time: '2020-08-10', grade: '三年二班', name: '小明', subjects: '语文', score: 80 },                { time: '2020-08-10', grade: '三年二班', name: '小明', subjects: '数学', score: 80 },                 { time: '2020-08-10', grade: '总成绩', name: '总成绩', subjects: '总成绩', score: 160 },                { time: '2020-08-10', grade: '三年一班', name: '小雷', subjects: '语文', score: 70 },                { time: '2020-08-10', grade: '三年一班', name: '小雷', subjects: '数学', score: 80 },                { time: '2020-08-10', grade: '总成绩', name: '总成绩', subjects: '总成绩', score: 150 },                 { time: '2020-08-11', grade: '三年三班', name: '小花', subjects: '语文', score: 60 },                 { time: '2020-08-11', grade: '三年三班', name: '小花', subjects: '数学', score: 60 },                 { time: '2020-08-11', grade: '总成绩', name: '总成绩', subjects: '总成绩', score: 120 }            ],            // 表格的信息 需要合并的需要放在 children 中            colConfigs: [                {                    type: 'label',                    children: [                        { prop: 'time', label: '时间' },                        { prop: 'grade', label: '年级' },                        { prop: 'name', label: '姓名' },                        { prop: 'subjects', label: '科目' },                        { prop: 'score', label: '成绩' }                    ]                },                // { type: 'label', prop: 'age', label: '年龄' }            ],            // 需要合并的行列信息 index必须是table表格对应的下标 不能随意修改            mergeCols: [                { index: 0, name: 'time' },                { index: 1, name: 'grade' },                { index: 2, name: 'name' },                { index: 3, name: 'subjects' },                { index: 4, name: 'score' },                // { index: 5, name: 'age' }            ],            // 用来记录每一个单元格的下标            tableMergeIndex: [],        };    },    methods: {        objectSpanMethods({ row, column, rowIndex, columnIndex }) {            let key = columnIndex + '_' + rowIndex;            if (this.tableMergeIndex[key]) {                return this.tableMergeIndex[key];            }        },        newTableMergeData() {            for (let i = 0; i < this.tableData.length; i++) {                for (let j = 0; j < this.mergeCols.length; j++) {                    // 初始化行、列坐标信息                    let rowIndex = 1;                    let columnIndex = 1;                    // 比较横坐标左方的第一个元素                    if (j > 0 && this.tableData[i][this.mergeCols[j]['name']] === this.tableData[i][this.mergeCols[j - 1]['name']]) {                        columnIndex = 0;                    }                    // 比较纵坐标上方的第一个元素                    if (i > 0 && this.tableData[i][this.mergeCols[j]['name']] === this.tableData[i - 1][this.mergeCols[j]['name']]) {                        rowIndex = 0;                    }                    // 比较横坐标右方元素                    if (columnIndex > 0) {                        columnIndex = this.onColIndex(this.tableData[i], j, j + 1, 1, this.mergeCols.length);                    }                    // 比较纵坐标下方元素                    if (rowIndex > 0) {                        rowIndex = this.onRowIndex(this.tableData, i, i + 1, 1, this.mergeCols[j]['name']);                    }                    let key = this.mergeCols[j]['index'] + '_' + i;                    this.tableMergeIndex[key] = [rowIndex, columnIndex];                }            }        },        /**         * 计算列坐标信息         * data 单元格所在行数据         * index 当前下标         * nextIndex 下一个元素坐标         * count 相同内容的数量         * maxLength 当前行的列总数         */        onColIndex(data, index, nextIndex, count, maxLength) {            // 比较当前单元格中的数据与同一行之后的单元格是否相同            if (nextIndex < maxLength && data[this.mergeCols[index]['name']] === data[this.mergeCols[nextIndex]['name']]) {                return this.onColIndex(data, index, ++nextIndex, ++count, maxLength);            }            return count;        },        /**         * 计算行坐标信息         * data 表格总数据         * index 当前下标         * nextIndex 下一个元素坐标         * count 相同内容的数量         * name 数据的key         */        onRowIndex(data, index, nextIndex, count, name) {            // 比较当前单元格中的数据与同一列之后的单元格是否相同            if (nextIndex < data.length && data[index][name] === data[nextIndex][name]) {                return this.onRowIndex(data, index, ++nextIndex, ++count, name);            }            return count;        }    },    mounted() {        if(this.mergeCols.length > 0) {            this.newTableMergeData();        }    }};</script><style lang="stylus" scoped>.table     height 100vh    width 100%    padding 40px    box-sizing border-box    /deep/ .el-table__body tr:hover > td        background-color: #fff;</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151

如果用不想合并的行需要在colConfigs中调整,如下:

// 增加一个年龄属性 但是不进行合并colConfigs: [    {        type: 'label',        children: [            { prop: 'time', label: '时间' },            { prop: 'grade', label: '年级' },            { prop: 'name', label: '姓名' },            { prop: 'subjects', label: '科目' },            { prop: 'score', label: '成绩' }        ]    },    { type: 'label', prop: 'age', label: '年龄' }]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

效果图如下:


如果想要合并,需要在mergeCols中添加数据,如下:

mergeCols: [    { index: 0, name: 'time' },    { index: 1, name: 'grade' },    { index: 2, name: 'name' },    { index: 3, name: 'subjects' },    { index: 4, name: 'score' },    { index: 5, name: 'age' } // 添加需要合并的age列信息 注意index的值],
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

新添加的属性合并后效果图如下:

以上就是el-table表格合并行列的内容,有不懂的地方欢迎留言讨论~

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发