話不多說, 直接上效果圖
-
這里是未展開的表格:
image.png -
展開之后:
image.png
image.png
完整的Demo代碼在最下方
拆分解析:
1. 從最簡單的合并表頭開始
這里因為沒有從官方文檔找到合適的方法, 我利用css樣式來實現(xiàn)
Dom部分代碼:
第一個單元格需要加上label-class-name屬性, 官方文檔 的解釋是:
當前列標題的自定義類名
第二個需要合并的表頭單元格不要加
label
<el-table-column prop="stageGroup" label="階段" align="center" header-align="right"
label-class-name="merge_thead">
</el-table-column>
<el-table-column prop="stageName" align="center">
</el-table-column>
- 接下來只需要把第一個單元格的內容挪到兩個單元格中間就行了
css樣式:
.mergeThead {
overflow: visible !important;
border-right: none !important;
}
.mergeThead .cell {
position: absolute;
z-index: 1;
margin-right: -25px;
}
2. 嵌套表格
elementUI table的折疊行功能只需要在航煤添加 type="expand"
屬性即可, 默認顯示為一個箭頭, 如果有可以自定義顯示內容的方法可以告訴我
<el-table-column type="expand">
我這里展開的內容是另外一個表格, 也就是嵌套表格, 其實很簡單
<el-table-column type="expand">
<template>
<el-table :data="data">
</el-table>
</template>
</el-table-column>
3. 每次只允許一行展開
展開一個表格就超過一屏了, 多個占個會影響操作, 所以這里我只讓他展開一行
elementUI 默認不限制展開的行數(shù), 如果要設置需要展開的行, 要用到官方提供的
expand-row-keys
屬性: 可以通過該屬性設置 Table 目前的展開行,需要設置 row-key 屬性才能使用,該屬性為展開行的 keys 數(shù)組被济。
row-key
屬性:為Function時, 可以獲取當前行內數(shù)據
(這里沒有引用官方的解釋)
expand-change
方法: 當用戶對某一行展開或者關閉的時候會觸發(fā)該事件
<el-table stripe border :data="outDataList" align="center" tooltip-effect="dark" style="width: 100%"
@expand-change="queryData" :expand-row-keys="expands" :row-key='getRowKeys'>
</el-table>
<script>
data: {
expands: [],
getRowKeys(row) {
return row.id
},
},
methods: {
queryData(row, expandedRows) {
// 這里默認接收兩個參數(shù),row時當前行數(shù)據, expandedRows是已經展開的行(數(shù)組)
let that = this
//只展開一行
if (expandedRows.length) {
// 說明展開了, 如果展開了多行, 這個數(shù)組會存放多個行id
// 我們不需要多余的展開, 因此清空他, 給他push一個當前行的id即可
that.expands = []
if (row) {
that.expands.push(row.id) //只展開當前行id
}
} else { //說明收起了
that.expands = []
}
}
}
</script>
4. 合并單元格
合并單元格需要使用 span-method
方法, 官網只給了一個很簡陋的例子, 無法滿足需求
span-method
方法: *通過給table傳入span-method方法可以實現(xiàn)合并行或列,方法的參數(shù)是一個對象钮追,里面包含當前行row元媚、當前列column刊棕、當前行號rowIndex甥角、當前列號columnIndex四個屬性嗤无。該函數(shù)可以返回一個包含兩個元素的數(shù)組当犯,第一個元素代表rowspan灶壶,第二個元素代表colspan驰凛。 也可以返回一個鍵名為rowspan和colspan的對象恰响。*
Dom部分代碼:
<el-table :data="innerDataList" align="center" stripe border :span-method="spanMethod"
tooltip-effect="dark" style="width: 100%" align="center">
</el-table>
JS部分代碼:
- 關于
getSpanData
這個方法, 我也是從網上借鑒來的, 我比較菜, 無法詳細表達出來, 我自己是通過畫圖才大致明白的 - 關于
spanMethod
這個方法, 可能有人認為這里面的單元格合并是寫死的, 我這里的需求確實是給定了哪些單元格需要合并, 反而我認為, 如果不能確定哪些單元格需要合并, 僅僅根據數(shù)據去判斷是否合并, 和可能會導致表格混亂 (如果確實要根據數(shù)據來, 只需要再增加判斷即可
)
<script>
data: {
spanData: [],
pos: null,
},
methods: {
// 計算需要合并的單元格
getSpanData(data) {
// 存放計算好的合并單元格的規(guī)則
this.spanData = []
for (var i = 0, len = data.length; i < len; i++) {
if (i === 0) {
this.spanData.push(1)
this.pos = 0
} else { // 判斷當前元素與上一個元素是否相同
if (data[i].stageGroup === data[i - 1].stageGroup) {
this.spanData[this.pos] += 1
this.spanData.push(0)
} else {
this.spanData.push(1)
this.pos = i
}
}
}
},
spanMethod({ row, column, rowIndex, columnIndex }) {
let _row = null
let _col = null
if (row.stageGroup == '第一階段') {
if (columnIndex === 0 || columnIndex === 3 || columnIndex === 5 || columnIndex === 6) {
_row = this.spanData[rowIndex]
_col = _row > 0 ? 1 : 0
return {
rowspan: _row,
colspan: _col
}
} else if (columnIndex === 10 && row.stageName !== '未接通') {
_row = this.spanData[rowIndex] - 1
_col = _row > 0 ? 1 : 0
return {
rowspan: 3,
colspan: 1
}
}
} else if (columnIndex === 0) {
_row = this.spanData[rowIndex]
_col = _row > 0 ? 1 : 0
return {
rowspan: _row,
colspan: _col
}
}
},
queryData(row, expandedRows) {
let that = this
//只展開一行
if (expandedRows.length) { //說明展開了
that.expands = []
if (row) {
that.expands.push(row.id) //只展開當前行id
}
} else { //說明收起了
that.expands = []
}
// 下面res是異步獲取的數(shù)據
let res = []
this.innerDataList = res
// 調用判斷合并單元格規(guī)則的方法
this.getSpanData(this.innerDataList)
}
}
</script>
下面是Demo完整代碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- 引入樣式 -->
<link rel="stylesheet" >
<style>
#app {}
.merge_thead {
overflow: visible !important;
border-right: none !important;
}
.merge_thead .cell {
position: absolute;
z-index: 1;
margin-right: -25px;
}
</style>
</head>
<body>
<div class="app">
<el-table stripe border :data="outDataList" align="center" tooltip-effect="dark" style="width: 100%"
@expand-change="queryData" :expand-row-keys="expands" :row-key='getRowKeys'>
<el-table-column prop="batchId" label="數(shù)據批次" min-width="90px" align="center">
<template slot-scope="props">
<span>{{props.row.batchId}}</span>
</template>
</el-table-column>
<el-table-column prop="distributeNumber" label="下發(fā)數(shù)量" align="center">
<template slot-scope="props">
<span>{{props.row.distributeNumber || 0}}</span>
</template>
</el-table-column>
<el-table-column prop="transformNumber" label="轉化數(shù)量" align="center">
<template slot-scope="props">
<span>{{props.row.transformNumber || 0}}</span>
</template>
</el-table-column>
<el-table-column prop="transformRate" label="轉化率" align="center">
<template slot-scope="props">
<span>{{props.row.transformRate || '---'}}</span>
</template>
</el-table-column>
<el-table-column prop="createTime" label="轉化統(tǒng)計截止時間" align="center">
<template slot-scope="props">
<span>{{props.row.createTime || '---'}}</span>
</template>
</el-table-column>
<el-table-column prop="查看詳情" type="expand" align="center">
<template>
<el-table :data="innerDataList" align="center" stripe border :span-method="spanMethod"
tooltip-effect="dark" style="width: 100%" align="center">
<el-table-column prop="stageGroup" label="階段" align="center" header-align="right"
label-class-name="merge_thead">
</el-table-column>
<el-table-column prop="stageName" align="center">
</el-table-column>
<el-table-column prop="distributeNumber" label="數(shù)據下發(fā)量" align="center">
</el-table-column>
<el-table-column prop="rate" label="總量占比" align="center">
</el-table-column>
<el-table-column prop="coverRate" label="覆蓋率" align="center">
</el-table-column>
<el-table-column prop="connectedRate" label="接通率" align="center">
</el-table-column>
<el-table-column prop="connectedTransRate" label="接通轉化率" align="center">
</el-table-column>
<el-table-column prop="transRate" label="整體轉化率" align="center">
</el-table-column>
<el-table-column prop="transNumberRate" label="轉化量占比" align="center">
</el-table-column>
<el-table-column prop="avgTransTime" label="平均轉化時長" align="center">
</el-table-column>
<el-table-column prop="callRate" label="整體撥打頻次" align="center">
</el-table-column>
</el-table>
</template>
</el-table-column>
</el-table>
</div>
</body>
<!-- 先引入 Vue -->
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<!-- 引入組件庫 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
new Vue({
el: '.app',
data: {
innerDataList: [],
outDataList: [
{
"id": 1,
"batchId": "234",
"intentId": 10057,
"distributeNumber": 100,
"transformNumber": 100,
"transformRate": "100%",
"createTime": "2019-11-21 11:26:27",
"modifyTime": "2019-11-21 11:26:29"
},
{
"id": 2,
"batchId": "123",
"intentId": 10057,
"distributeNumber": "2345",
"transformNumber": "468",
"transformRate": "57.6%",
"createTime": "2019-11-21 11:29:30",
"modifyTime": "更新時間"
}
],
spanData: [],
pos: null,
expands: [],
getRowKeys(row) {
return row.id
},
},
methods: {
// 計算需要合并的單元格
getSpanData(data) {
// 存放計算好的合并單元格的規(guī)則
this.spanData = []
for (var i = 0, len = data.length; i < len; i++) {
if (i === 0) {
this.spanData.push(1)
this.pos = 0
} else { // 判斷當前元素與上一個元素是否相同
if (data[i].stageGroup === data[i - 1].stageGroup) {
this.spanData[this.pos] += 1
this.spanData.push(0)
} else {
this.spanData.push(1)
this.pos = i
}
}
}
},
spanMethod({
row,
column,
rowIndex,
columnIndex
}) {
let _row = null
let _col = null
if (row.stageGroup == '第一階段') {
if (columnIndex === 0 || columnIndex === 3 || columnIndex === 5 || columnIndex === 6) {
_row = this.spanData[rowIndex]
_col = _row > 0 ? 1 : 0
return {
rowspan: _row,
colspan: _col
}
} else if (columnIndex === 10 && row.stageName !== '未接通') {
_row = this.spanData[rowIndex] - 1
_col = _row > 0 ? 1 : 0
return {
rowspan: 3,
colspan: 1
}
}
} else if (columnIndex === 0) {
_row = this.spanData[rowIndex]
_col = _row > 0 ? 1 : 0
return {
rowspan: _row,
colspan: _col
}
}
},
queryData(row, expandedRows) {
let that = this
//只展開一行
if (expandedRows.length) { //說明展開了
that.expands = []
if (row) {
that.expands.push(row.id) //只展開當前行id
}
} else { //說明收起了
that.expands = []
}
// 下面res是異步獲取的數(shù)據
let res = [{
"stage": "第一階段",
"batchReportDetails": [{
"id": 1,
"batchReportId": 1,
"stageGroup": "第一階段",
"stageName": "第一階段客服A",
"distributeNumber": 35005,
"rate": "13.82",
"coverRate": "100.00",
"connectedRate": "42.55",
"connectedTransRate": 0,
"transRate": 0,
"transNumberRate": 0,
"avgTransTime": 0,
"callRate": 0,
"createTime": 0,
"modifyTime": 0,
"intentId": 10057
},
{
"id": 2,
"batchReportId": 1,
"stageGroup": "第一階段",
"stageName": "第一階段客服B",
"distributeNumber": 35005,
"rate": "7.67",
"coverRate": "100.00",
"connectedRate": "42.55",
"connectedTransRate": 0,
"transRate": 0,
"transNumberRate": 0,
"avgTransTime": 0,
"callRate": 0,
"createTime": 0,
"modifyTime": 0,
"intentId": 10057
},
{
"id": 3,
"batchReportId": 1,
"stageGroup": "第一階段",
"stageName": "第一階段客服C",
"distributeNumber": 35005,
"rate": "57.45",
"coverRate": "100.00",
"connectedRate": "42.55",
"connectedTransRate": 0,
"transRate": 0,
"transNumberRate": 0,
"avgTransTime": 0,
"callRate": 0,
"createTime": 0,
"modifyTime": 0,
"intentId": 10057
},
{
"id": 4,
"batchReportId": 1,
"stageGroup": "第一階段",
"stageName": "未接通",
"distributeNumber": 35005,
"rate": "21.06",
"coverRate": "100.00",
"connectedRate": "42.55",
"connectedTransRate": 13,
"transRate": 13,
"transNumberRate": 13,
"avgTransTime": 134,
"callRate": 134,
"createTime": 134,
"modifyTime": 134,
"intentId": 10057
}
]
}, {
"stage": "第二階段",
"batchReportDetails": [{
"id": 1,
"batchReportId": 1,
"stageGroup": "第二階段",
"stageName": "第二階段客服A",
"distributeNumber": 35005,
"rate": "13.82",
"coverRate": "100.00",
"connectedRate": "42.55",
"connectedTransRate": 134,
"transRate": 134,
"transNumberRate": 14,
"avgTransTime": 14,
"callRate": 14,
"createTime": 14,
"modifyTime": 14,
"intentId": 10057
},
{
"id": 2,
"batchReportId": 1,
"stageGroup": "第二階段",
"stageName": "第二階段客服B",
"distributeNumber": 35005,
"rate": "7.67",
"coverRate": "100.00",
"connectedRate": "42.55",
"connectedTransRate": 14,
"transRate": 14,
"transNumberRate": 14,
"avgTransTime": 14,
"callRate": 5,
"createTime": 5,
"modifyTime": 5,
"intentId": 10057
},
{
"id": 3,
"batchReportId": 1,
"stageGroup": "第二階段",
"stageName": "第二階段未接通",
"distributeNumber": 35005,
"rate": "57.45",
"coverRate": "100.00",
"connectedRate": "42.55",
"connectedTransRate": 5,
"transRate": 5,
"transNumberRate": 5,
"avgTransTime": 5,
"callRate": 5,
"createTime": 5,
"modifyTime": 5,
"intentId": 10057
},
{
"id": 5,
"batchReportId": 1,
"stageGroup": "第二階段",
"stageName": "第二階段客服C",
"distributeNumber": 35005,
"rate": "21.06",
"coverRate": "100.00",
"connectedRate": "42.55",
"connectedTransRate": 5,
"transRate": 57,
"transNumberRate": 57,
"avgTransTime": 57,
"callRate": 57,
"createTime": 57,
"modifyTime": 57,
"intentId": 10057
},
{
"id": 6,
"batchReportId": 1,
"stageGroup": "第二階段",
"stageName": "第二階段客服C",
"distributeNumber": 35005,
"rate": "21.06",
"coverRate": "100.00",
"connectedRate": "42.55",
"connectedTransRate": 57,
"transRate": 57,
"transNumberRate": 57,
"avgTransTime": 57,
"callRate": 579,
"createTime": 579,
"modifyTime": 579,
"intentId": 10057
}
]
}, {
"stage": "第三階段",
"batchReportDetails": [{
"id": 1,
"batchReportId": 1,
"stageGroup": "第三階段",
"stageName": "客服A",
"distributeNumber": 35005,
"rate": "13.82",
"coverRate": "100.00",
"connectedRate": "42.55",
"connectedTransRate": 579,
"transRate": 579,
"transNumberRate": 579,
"avgTransTime": 579,
"callRate": 579,
"createTime": 579,
"modifyTime": 579,
"intentId": 10057
},
{
"id": 2,
"batchReportId": 1,
"stageGroup": "第三階段",
"stageName": "客服B",
"distributeNumber": 35005,
"rate": "7.67",
"coverRate": "100.00",
"connectedRate": "42.55",
"connectedTransRate": 579,
"transRate": 16,
"transNumberRate": 16,
"avgTransTime": 16,
"callRate": 16,
"createTime": 16,
"modifyTime": 16,
"intentId": 10057
}
]
}, {
"stage": "回收",
"batchReportDetails": [{
"id": 1,
"batchReportId": 1,
"stageGroup": "回收",
"stageName": "客服A",
"distributeNumber": 35005,
"rate": "13.82",
"coverRate": "100.00",
"connectedRate": "42.55",
"connectedTransRate": 16,
"transRate": 166,
"transNumberRate": 166,
"avgTransTime": 166,
"callRate": 166,
"createTime": 166,
"modifyTime": 166,
"intentId": 10057
},
{
"id": 2,
"batchReportId": 1,
"stageGroup": "回收",
"stageName": "客服B",
"distributeNumber": 35005,
"rate": "7.67",
"coverRate": "100.00",
"connectedRate": "42.55",
"connectedTransRate": 166,
"transRate": 165,
"transNumberRate": 165,
"avgTransTime": 165,
"callRate": 165,
"createTime": 165,
"modifyTime": 165,
"intentId": 10057
},
{
"id": 3,
"batchReportId": 1,
"stageGroup": "回收",
"stageName": "未接通",
"distributeNumber": 35005,
"rate": "57.45",
"coverRate": "100.00",
"connectedRate": "42.55",
"connectedTransRate": 165,
"transRate": 165,
"transNumberRate": 165,
"avgTransTime": 165,
"callRate": 165,
"createTime": 1657,
"modifyTime": 1657,
"intentId": 10057
},
{
"id": 5,
"batchReportId": 1,
"stageGroup": "回收",
"stageName": "客服C",
"distributeNumber": 35005,
"rate": "21.06",
"coverRate": "100.00",
"connectedRate": "42.55",
"connectedTransRate": 1657,
"transRate": 1657,
"transNumberRate": 1657,
"avgTransTime": 1657,
"callRate": 1657,
"createTime": 1657,
"modifyTime": 1657,
"intentId": 10057
},
{
"id": 6,
"batchReportId": 1,
"stageGroup": "回收",
"stageName": "客服C",
"distributeNumber": 35005,
"rate": "21.06",
"coverRate": "100.00",
"connectedRate": "42.55",
"connectedTransRate": 1657,
"transRate": 1657,
"transNumberRate": 44,
"avgTransTime": 44,
"callRate": 44,
"createTime": 44,
"modifyTime": 44,
"intentId": 10057
}
]
}]
this.innerDataList = []
// 這里是因為后端給我的數(shù)據結構原因, 所一個拼接, 請注意自己的數(shù)據結構
for (let n of res) {
this.innerDataList.push(...n.batchReportDetails)
}
this.getSpanData(this.innerDataList)
console.log(this.innerDataList);
},
}
})
</script>
</html>