ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] >[success] # Element UI table合并行(上下行) 通过给`table`传入`span-method`方法可以实现合并行或列,方法的参数是一个对象,里面包含当前行`row`、当前列`column`、当前行号`rowIndex`、当前列号`columnIndex`四个属性。该函数可以返回一个包含两个元素的数组,第一个元素代表`rowspan`,第二个元素代表`colspan`。 也可以返回一个键名为`rowspan`和`colspan`的对象。 >[success] ## 官方案例 如图,上面的表格时合并列,下面的表格是合并行 ![](https://img.kancloud.cn/60/1d/601ded7a48b8f00262df3f058aef2021_1067x700.png) html ~~~ <template> <div> <!-- 合并列 --> <el-table :data="tableData" :span-method="arraySpanMethod" border style="width: 100%"> <el-table-column prop="id" label="ID" width="180"/> <el-table-column prop="name" label="姓名"/> <el-table-column prop="amount1" sortable label="数值 1"/> <el-table-column prop="amount2" sortable label="数值 2"/> <el-table-column prop="amount3" sortable label="数值 3"/> </el-table> <br> <br> <br> <br> <!-- 合并行 --> <el-table :data="tableData" :span-method="objectSpanMethod" border style="width: 100%; margin-top: 20px"> <el-table-column prop="id" label="ID" width="180"/> <el-table-column prop="name" label="姓名"/> <el-table-column prop="amount1" label="数值 1(元)"/> <el-table-column prop="amount2" label="数值 2(元)"/> <el-table-column prop="amount3" label="数值 3(元)"/> </el-table> </div> </template> ~~~ Javascript ~~~ <script> export default{ data() { return { tableData: [ { id: '12987122', name: '王小虎', amount1: '234', amount2: '3.2', amount3: 10 }, { id: '12987123', name: '王小虎', amount1: '165', amount2: '4.43', amount3: 12 }, { id: '12987124', name: '王小虎', amount1: '324', amount2: '1.9', amount3: 9 }, { id: '12987125', name: '王小虎', amount1: '621', amount2: '2.2', amount3: 17 }, { id: '12987126', name: '王小虎', amount1: '539', amount2: '4.1', amount3: 15 } ] } }, methods: { // 合并列方法 arraySpanMethod({ row, column, rowIndex, columnIndex }) { if (rowIndex % 2 === 0) { // 行索引为偶数时 if (columnIndex === 0) { // 列索引为 第1列时 return [1, 2] // [行跨度,列跨度 ] } else if (columnIndex === 1) { return [0, 0] // [行跨度,列跨度 ] } } }, // 合并行的计算方法 objectSpanMethod({ row, column, rowIndex, columnIndex }) { if (columnIndex === 0) { // 用于设置要合并的列 这里是指第一列合并 if (rowIndex % 2 === 0) { // 用于设置合并开始的行号,具体结合下方案例理解 return { rowspan: 2, // 要合并的行数 colspan: 1 // 要合并的列数 }; } else { return { rowspan: 0, // 要合并的行数,为 0 则直接不显示 colspan: 0 // 要合并的列数,为 0 则直接不显示 }; } } } } } </script> ~~~ <br/> >[success] ## 每列按照同一种规则合并行(上下行) 假如我想写下面这样的表格,第1、2、3和最后一列的合并方式都一样。 ![](https://img.kancloud.cn/8a/e0/8ae0185425fb734806365df094dd21bf_1913x544.png) html ~~~ <template> <div> <el-table :data="tableData" border :span-method="objectSpanMethod"> <el-table-column type="selection" align="center" width="55" /> <el-table-column prop="taxerName" label="企业名称" align="center" /> <el-table-column prop="taxerId" label="税号" align="center" /> <el-table-column prop="terminalId" label="盘编号" align="center" /> <el-table-column prop="invoiceType" label="发票类型" align="center" width="100px"/> <el-table-column prop="status" label="抄报状态" align="center" width="100px" /> <el-table-column prop="taxReturnResult" label="抄报结果" align="center" /> <el-table-column prop="unlockResult" label="反写结果" align="center" /> <el-table-column prop="invoiceEndDate" label="开票截止日期" align="center" /> <el-table-column prop="taxReturnDate" label="最新报税日期" align="center" /> <el-table-column fixed="right" label="操作" align="center"> <template slot-scope="scope"> <el-button type="text" size="small">查看详情</el-button> </template> </el-table-column> </el-table> </div> </template> ~~~ Javascript ~~~ <script> export default{ data() { return { tableData: [ { "deviceId": "463346577777888888888", "taxerName": "123", "taxerId": "4762455555555543333333", "terminalId": "346537568756876888888", "invoiceTypes": ["025", "026", "004", "007"], "rowspan": 1 // rowspan 1:表示不合并 }, { "deviceId": "645767777754675677777", "taxerName": "234", "taxerId": "234444442342344444", "terminalId": "432524355555333333", "invoiceTypes": ["004", "007", "025", "026"], "invoiceType": "004", "status": 3, "taxReturnResult": "成功", "unlockResult": "失败", "invoiceEndDate": "2019-04-15", "taxReturnDate": "2019-03-31", "rowspan": 4 // rowspan 4:表示合并下方的三行,共合并四行 }, { "deviceId": "645767777754675677777", "taxerName": "234", "taxerId": "234444442342344444", "terminalId": "432524355555333333", "invoiceTypes": ["004", "007", "025", "026"], "invoiceType": "026", "status": 3, "taxReturnResult": "成功", "unlockResult": "失败", "invoiceEndDate": "2019-04-15", "taxReturnDate": "2019-03-31", "rowspan": 0 // rowspan 0:表示已被上面的行合并,该单元格不显示 }, { "deviceId": "645767777754675677777", "taxerName": "234", "taxerId": "234444442342344444", "terminalId": "432524355555333333", "invoiceTypes": ["004", "007", "025", "026"], "invoiceType": "007", "status": 3, "taxReturnResult": "成功", "unlockResult": "失败", "invoiceEndDate": "2019-04-15", "taxReturnDate": "2019-03-31", "rowspan": 0 // rowspan 0:表示已被上面的行合并,该单元格不显示 }, { "deviceId": "645767777754675677777", "taxerName": "234", "taxerId": "234444442342344444", "terminalId": "432524355555333333", "invoiceTypes": ["004", "007", "025", "026"], "invoiceType": "025", "status": 3, "taxReturnResult": "成功", "unlockResult": "失败", "invoiceEndDate": "2019-04-15", "taxReturnDate": "2019-03-31", "rowspan": 0 // rowspan 0:表示已被上面的行合并,该单元格不显示 }, { "deviceId": "756465866856767677777", "taxerName": "555", "taxerId": "453623465234645555455", "terminalId": "6436543565455555", "invoiceTypes": ["004", "007", "025", "026"], "invoiceType": "007", "status": 3, "taxReturnResult": null, "unlockResult": null, "invoiceEndDate": "2019-04-15", "taxReturnDate": "2019-03-31", "rowspan": 3 // rowspan 3:表示合并下方的2行,共合并3行 }, { "deviceId": "756465866856767677777", "taxerName": "555", "taxerId": "453623465234645555455", "terminalId": "6436543565455555", "invoiceTypes": ["004", "007", "025", "026"], "invoiceType": "026", "status": 3, "taxReturnResult": null, "unlockResult": null, "invoiceEndDate": "2019-04-15", "taxReturnDate": "2019-03-31", "rowspan": 0 // rowspan 0:表示已被上面的行合并,该单元格不显示 }, { "deviceId": "756465866856767677777", "taxerName": "555", "taxerId": "453623465234645555455", "terminalId": "6436543565455555", "invoiceTypes": ["004", "007", "025", "026"], "invoiceType": "004", "status": 3, "taxReturnResult": null, "unlockResult": null, "invoiceEndDate": "2019-04-15", "taxReturnDate": "2019-03-31", "rowspan": 0 // rowspan 0:表示已被上面的行合并,该单元格不显示 }, { "deviceId": "46365546555555555", "taxerName": "666", "taxerId": "787654545314312", "terminalId": "789765454151453", "invoiceTypes": ["004", "026"], "invoiceType": "026", "status": 3, "taxReturnResult": "成功", "unlockResult": "失败", "invoiceEndDate": "2019-04-18", "taxReturnDate": "2019-03-31", "rowspan": 2// rowspan 2:表示合并下方的1行,共合并2行 }, { "deviceId": "46365546555555555", "taxerName": "666", "taxerId": "787654545314312", "terminalId": "789765454151453", "invoiceTypes": ["004", "026"], "invoiceType": "004", "status": 3, "taxReturnResult": "成功", "unlockResult": "失败", "invoiceEndDate": "2019-04-18", "taxReturnDate": "2019-03-31", "rowspan": 0 // rowspan 0:表示已被上面的行合并,该单元格不显示 } ] } }, methods: { objectSpanMethod ({ row, column, rowIndex, columnIndex }) { // 之前我这么些判断,有点小蠢... // if (columnIndex === 0 || columnIndex === 1 || columnIndex === 2 || columnIndex === 3 || columnIndex === 10) { // 要合并的列的索引 let arr = [0, 1, 2, 3, 10] // 设置要合并的列 if (arr.indexOf(columnIndex) !== -1) { // 用于设置合并开始的行号,rowspan 不为 0,不是第一行时, 则该行需要向下合并 if (column.rowSpan !== 0) { return { rowspan: row.rowspan, // 要合并的行数 colspan: 1 } } else { return { rowspan: 0, // column.rowspan === 0 隐藏该单元格 colspan: 0 } } } } } } </script> ~~~ <br/> >[success] ## 每列都有自己的合并方式(合并行) 如图我想写一个这种表格,第一列和第二列的合并行数都不同。 ![](https://img.kancloud.cn/f6/8d/f68d834b2929eefa9481ec1780421db7_978x392.png) html ~~~ <template> <div> <el-table :data="permissionData" border :span-method="objectSpanMethod"> <el-table-column prop="deviceId" label="企业名称" align="center" /> <el-table-column prop="taxerName" label="税号" align="center" /> <el-table-column prop="taxerId" label="盘编号" align="center" /> </el-table> </div> </template> ~~~ Javascript ~~~ <script> export default{ data() { return { permissionData: [ { 'deviceId': '首页', 'taxerName': '', 'taxerId': '', 'rowspan': [1, 1] }, { 'deviceId': '管理功能', 'taxerName': '预开审核', 'taxerId': '预开审核管理', 'rowspan': [6, 1] }, { 'deviceId': '管理功能', 'taxerName': '发票查询', 'taxerId': '已开发票查询', 'rowspan': [0, 3] }, { 'deviceId': '管理功能', 'taxerName': '发票查询', 'taxerId': '未上传发票查询', 'rowspan': [0, 0] }, { 'deviceId': '管理功能', 'taxerName': '发票查询', 'taxerId': '验签失败发票查询', 'rowspan': [0, 0] }, { 'deviceId': '管理功能', 'taxerName': '商户综合管理', 'taxerId': '税控设备列表', 'rowspan': [0, 2] }, { 'deviceId': '管理功能', 'taxerName': '商户综合管理', 'taxerId': '数据抄报', 'rowspan': [0, 0] } ] } }, methods: { // 合并表格 objectSpanMethod ({ row, column, rowIndex, columnIndex }) { let arr = [0, 1] // 设置要合并的列 if (arr.indexOf(columnIndex) !== -1) { if (column.rowSpan !== 0) { // 第一列 if (columnIndex === 0) { return { rowspan: row.rowspan[0], colspan: 1 } } // 第二列 else if(columnIndex === 1){ return { rowspan: row.rowspan[1], colspan: 1 } } } else { return { rowspan: 0, colspan: 0 } } } } } } </script> ~~~ <br/> >[success] ## 须知 ~~~ 以上几种'表格合并',不管是'每列按照同一种方式来合并',还是'每列都有自己的合并方式',他们都有一个 共同点,'同一种方式合并行'需要在数据中返回一个'数值','每列都有自己的合并方式'需要返回一个数组, 并且需要在 'objectSpanMethod'方法中'判断是第几列',每列使用的'rowspan'都不同,上面写的都是 '静态数据',那数据是后台给的动态数据,rowspan又该如何计算,如何把数据整合成想要的格式呢? ~~~ <br/> >[success] ## 合并表格案例(cv工程师直接来这里) ~~~ 下面的例子中如果'想多列合并',而且'根据数据动态合并',就需要手动写一个'this.getSpanArr()'方法, 然后在data中再定义一个'记录行合并数的数组' ~~~ ![](https://img.kancloud.cn/f6/8d/f68d834b2929eefa9481ec1780421db7_978x392.png) html ~~~ <template> <div> <el-table :data="permissionData" border :span-method="cellMerge"> <el-table-column prop="deviceId" label="企业名称" align="center" /> <el-table-column prop="taxerName" label="税号" align="center" /> <el-table-column prop="taxerId" label="盘编号" align="center" /> </el-table> </div> </template> ~~~ Javascript ~~~ <script> export default{ data() { return { permissionData: [ // 接口数据 { 'deviceId': '首页', 'taxerName': '', 'taxerId': '' }, { 'deviceId': '管理功能', 'taxerName': '预开审核', 'taxerId': '预开审核管理' }, { 'deviceId': '管理功能', 'taxerName': '发票查询', 'taxerId': '已开发票查询' }, { 'deviceId': '管理功能', 'taxerName': '发票查询', 'taxerId': '未上传发票查询', }, { 'deviceId': '管理功能', 'taxerName': '发票查询', 'taxerId': '验签失败发票查询' }, { 'deviceId': '管理功能', 'taxerName': '商户综合管理', 'taxerId': '税控设备列表' }, { 'deviceId': '管理功能', 'taxerName': '商户综合管理', 'taxerId': '数据抄报' } ], spanArr: [], // deviceId的合并数 spanArr2: [] // taxerName的合并数 } }, created(){ this.getSpanArr(this.permissionData,this.spanArr, 'deviceId') this.getSpanArr(this.permissionData,this.spanArr2, 'taxerName') }, methods: { /** * 记录行合并数方法 * @param {array} data - 后台拿到的数据 * @param {array} arr - 存放每一行记录的合并数 * @param {string} property - 过滤属性是否重复,参数为要过滤的属性 */ getSpanArr(data, arr, property) {  let pos = 0 for (var i = 0; i < data.length; i++) {     if (i === 0) {         arr.push(1)         pos = 0     } else {     // 判断当前元素与上一个元素是否相同 if (data[i][property] === data[i - 1][property]) {         arr[pos] += 1         arr.push(0)         } else {         arr.push(1) pos = i         }     } } }, // 合并行或列方法 cellMerge({ row, column, rowIndex, columnIndex }) {      if (columnIndex === 0) {         const _row = this.spanArr[rowIndex];          const _col = _row > 0 ? 1 : 0         return {             rowspan: _row,              colspan: _col         }     } else if(columnIndex === 1){         const _row = this.spanArr2[rowIndex]          const _col = _row > 0 ? 1 : 0         return {             rowspan: _row,              colspan: _col         } } } } } </script> ~~~ >[success] ## 简化合并行方法 上面的 **合并行方法** 如果有 **多列需要合并行** ,就要写多个 **this.getSpanArr** 方法,多个 **spanArr** 数组,非常麻烦,可以使用下面这种方法来实现 **合并行** **tableDemo.vue** ~~~ <template> <div> <el-table :data="dataSource" height="846" ref="tableList" border :header-cell-style="{ background: '#f5f7fa' }" :span-method="cellMerges"> <el-table-column label="二级指标" width="200" prop="twoLevel" show-overflow-tooltip align="center" /> <el-table-column label="三级指标" width="240" prop="threeLevel" show-overflow-tooltip align="center" /> <el-table-column label="评分项目" width="240" prop="evaluateProject" show-overflow-tooltip align="center" /> <el-table-column label="评分标准" align="left"> <template slot-scope="scope"> <div style="text-indent: 14px">{{ scope.row.evaluateStandard || '' }}</div> </template> </el-table-column> <el-table-column label="分值" width="90" prop="score" show-overflow-tooltip align="center" /> <el-table-column label="土建" width="90" prop="structureScore" show-overflow-tooltip align="center"> <template slot-scope="scope"> <span>{{ scope.row.structureScore || scope.row.structureScore === 0 ? scope.row.structureScore : '-' }}</span> </template> </el-table-column> <el-table-column label="机电" width="90" show-overflow-tooltip align="center"> <template slot-scope="scope"> <span>{{ scope.row.electroScore || scope.row.electroScore === 0 ? scope.row.electroScore : '-' }}</span> </template> </el-table-column> <el-table-column label="均分" width="90" show-overflow-tooltip align="center"> <template slot-scope="scope"> <span>{{ scope.row.averageScore || scope.row.averageScore === 0 ? scope.row.averageScore : '-' }}</span> </template> </el-table-column> <el-table-column label="操作" width="150" show-overflow-tooltip align="center"> <template slot-scope="scope"> <el-button type="text" size="small" @click.native.prevent="goGrade(scope.$index, dataSource)"> 评分 </el-button> <el-button type="text" size="small" @click.native.prevent="goDeduction(scope.$index, dataSource)"> 扣分详情 </el-button> </template> </el-table-column> </el-table> </div> </template> <script> import Vue from 'vue' import { Table, TableColumn ,Button } from 'element-ui' import { mergeRows } from '../js/utils' // 按需引入 Vue.use(Table) Vue.use(Button) Vue.use(TableColumn) export default { data() { return { dataSource: [ { twoLevel: '能力指标 27', threeLevel: '制度建设与落实 15', evaluateProject: '1.1 责任划分', secondCode: '27', thirdCode: '15', itemCode: '1.1', standardCode: '1.1.1', evaluateStandard: '落实了全省隧道责任主体和监管主体,管理职责划分明确,得40分;落实了责任主体和监管主体,但管理职责划分不明确,得20分;落实了责任主体,但管理职责不明确,得10分;责任主体和监管主体不明晰,得0分', score: 40, structureScore: '40', }, { twoLevel: '能力指标 27', threeLevel: '制度建设与落实 15', evaluateProject: '1.2 监管能力', evaluateStandard: '针对隧道养护管理工作有相关制度或指导性意见,较好,得40分;有相关制度或指导性意见,基本完善,得30分;有相关制度或指导性意见,但不完善,得10分;无相关制度或指导性意见,得0分', score: 40, secondCode: '27', thirdCode: '15', itemCode: '1.2', standardCode: '1.2.1', structureScore: '40', } ] } }, methods: { cellMerges({ rowIndex, columnIndex}) { const mergeCfg = [ { searchKey: 'secondCode', columnIndex: 0 }, { searchKey: 'thirdCode', columnIndex: 1 }, { searchKey: 'itemCode', columnIndex: 2 } ] return mergeRows(rowIndex, columnIndex, this.dataSource, mergeCfg) } } } </script> ~~~ **合并行方法** ~~~ /** * 合并行方法 * @param {*} rowIndex 行索引 * @param {*} columnIndex 列索引 * @param {*} dataSource 数据源 * @param {*} mergeCfg 合并配置 例如:[{searchKey: 'score', columnIndex: 0 }] searchKey:需检索的属性,columnIndex:代表要合并的列数 */ export function mergeRows(rowIndex, columnIndex, dataSource, mergeCfg) { for (let item of mergeCfg) { let searchKey = item.searchKey if (columnIndex === item.columnIndex) { // 要合并的列 if (rowIndex !== 0 && dataSource[rowIndex][searchKey] === dataSource[rowIndex - 1][searchKey]) { // 非第一行合并规则(非第一行,并且上一行跟当前行值相等,如果不相等就走else) return [0, 0] } else { // 第一行合并规则 let rowIndexCount = rowIndex let count = 0 while (rowIndexCount + 1 < dataSource.length) { // 用当前行数据跟后续行数数据对比 if (dataSource[rowIndexCount + 1][searchKey] === dataSource[rowIndexCount][searchKey]) { rowIndexCount++ count++ } else { // 数据不相等跳出循环 break } } return [count + 1, 1] } } } } ~~~