赞
踩
在写项目的时候有时候会经常遇到把行和列合并起来的情况,因为有些数据是重复渲染的,不合并行列会使表格看起来非常的混乱,如下:
而我们想要的数据是下面这种情况,将重复的行进行合并,使表格看起来简单明了,如下:
所谓的合并行就是将多行相同的数据变成一行来显示,页面的布局比较简单
- <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>
2:模拟data数据
span-method
是el-table上属性,其值是一个函数,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: {}, // 用来记录需要合并行的下标
-
- tableProps: ['time', 'grade', 'name', 'subjects', 'score'] // 表格中的列名
首先需要对数据就行处理,就是比较当前行与上一行的值是否相等(如果是第一行数据,直接将值赋值为1)
在watch
中监听表格中的数据,当不为空的的时候,调用数据初始化数据的方法,如下:
- watch:{
- "tableData":function (newVal,oldVal){
- console.log("nnnnnnnnnnnn",newVal)
- console.log("oooooooooooo",oldVal)
- if(newVal.length>0){
- this.getSpanArr(this.tableData);
- }
- }
- },
- // getSpanArr方法
- getSpanArr(data) {
- this.tableProps.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方法了,如下:
- // objectSpanMethod方法
- /*默认接受四个值
- ----row==当前行的数据
- ----column==当前列的数据
- ----rowIndex==行的下标
- ----columnIndex==列的下标
- */
- // 默认接受四个值 { 当前行的值, 当前列的值, 行的下标, 列的下标 }
- objectSpanMethod({ row, column, rowIndex, columnIndex }) {
- // 判断列的属性
- if(this.tableProps.indexOf(column.property) !== -1) {
- // 判断其值是不是为0
- if(this.mergeObj[column.property][rowIndex]) {
- return [this.mergeObj[column.property][rowIndex], 1]
- } else {
- // 如果为0则为需要合并的行
- return [0, 0];
- }
- // 只有 第一列 第二列 第三列 合并行
- // if(columnIndex===1||columnIndex===2||columnIndex===3){
- // // 判断列的属性
- // if(this.tableProps.indexOf(column.property) !== -1) {
- // // 判断其值是不是为0
- // if(this.mergeObj[column.property][rowIndex]) {
- // return {
- // rowspan: this.mergeObj[column.property][rowIndex],
- // colspan: 1
- // };
- // } else {
- // // 如果为0则为需要合并的行
- // return {
- // rowspan: 0,
- // colspan: 0
- // };
- // }
- // }
- // }
- }
- }
合并后的结果就是我们想要的形式:
- <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'],
- };
- },
- watch:{
- "tableData":function (newVal,oldVal){
- console.log("nnnnnnnnnnnn",newVal)
- console.log("oooooooooooo",oldVal)
- if(newVal.length>0){
- this.getSpanArr(this.tableData);
- }
- }
- },
- 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];
- }
- }
- }
- },
-
- };
- </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:模拟data数据
span-method
是el-table上属性,其值是一个函数,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: 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
- }
- ],
可以看到上面的数据多了一行总成绩,现在的数据在页面显示效果如下:
可以看到总成绩的三个列并没有合并,并不是我们想要的效果,所以需要换一种思路来处理数据
页面的布局也有所调整,如下:
- <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>
- // 表格的信息 需要合并的需要放在 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: [],
- watch:{
- "tableData":function (newVal,oldVal){
- console.log("nnnnnnnnnnnn",newVal)
- console.log("oooooooooooo",oldVal)
- if(this.mergeCols.length > 0) {
- this.newTableMergeData();
- }
- }
- },
- // 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;
- }
数据处理好之后就可以调用objectSpanMethods方法了,如下:
- objectSpanMethods({ row, column, rowIndex, columnIndex }) {
- let key = columnIndex + '_' + rowIndex;
- if (this.tableMergeIndex[key]) {
- return this.tableMergeIndex[key];
- }
- }
- <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>
如果不想合并的行需要在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: '年龄' }
- ]
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的值
- ],
- data{
- return {
- spanArr: [],
- position: 0,
- }
- }
-
- rowspan(data) {
- this.spanArr=[];
- data.forEach((item,index) => {
- if( index === 0){
- this.spanArr.push(1);
- this.position = 0;
- }else{
- if(data[index].FId === data[index-1].FId ){
- this.spanArr[this.position] += 1;
- this.spanArr.push(0);
- }else{
- this.spanArr.push(1);
- this.position = index;
- }
- }
- })
- },
- objectSpanMethod({ row, column, rowIndex, columnIndex }) {
- if (columnIndex === 0||columnIndex === 1) {
- const _row = this.spanArr[rowIndex];
- const _col = _row>0 ? 1 : 0;
- return {
- rowspan: _row,
- colspan: _col
- }
- }
- },
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。