实际的前端开发过程中,table表格的数据都有后端返回,所以table表格的表头以及合并单元格需要动态去渲染。简单的一级表头可使用v-for循环去渲染el-table-column
,多头表格可以将其封装成递归组件进行渲染。而单元格的合并也可动态去计算。
父组件的写法
<template>
<div class="array-table-area" id="array-table-area">
<el-table
:data="tbody"
:span-method="objectSpanMethod"
border
stripe>
<--将el-table-column单独抽取成组件,使用vue的插槽功能-->
<template v-for="(item, index) in thead">
<array-table-child :list="item" :key="'tables' + index"></array-table-child>
</template>
</el-table>
</div>
</template>
<script>
import arrayTableChild from './public/array-table-child.vue' // 剥离的递归组件
export default {
name: 'achievements',
data () {
return {
thead: [],
tbody: [],
columnFiled: '',
rowFiled: [],
spanArr: [],
position: 0
}
},
props: {
tableData: {
type: Object,
default: null
}
},
components: {
arrayTableChild
},
methods: {
// 计算合并所需数据
rowspan () {
this.tbody.forEach((item, index) => {
if (index === 0) {
this.spanArr.push(1)
this.position = 0
} else {
// 这里是判断的条件
if ((this.tbody[index][this.columnFiled] === this.tbody[index - 1][this.columnFiled])) {
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) {
const _row = this.spanArr[rowIndex]
const _col = _row > 0 ? 1 : 0
this.rowFiled.includes(row[this.columnFiled])
if (this.rowFiled.includes(row[this.columnFiled])) {
return {
rowspan: 1,
colspan: 2
}
} else {
return {
rowspan: _row,
colspan: _col
}
}
} else if (columnIndex === 1) {
if (this.rowFiled.includes(row[this.columnFiled])) {
return {
rowspan: 0,
colspan: 0
}
}
}
}
},
watch: {
tableData: { // 监听传入的数据,动态渲染表格
handler (oldVal, newVal) {
this.thead = newVal.thead
this.tbody = newVal.tbody
this.columnFiled = newVal.columnFiled
this.rowFiled = newVal.rowFiled
setTimeout(() => {
this.spanArr = []
this.position = 0
this.rowspan()
})
},
deep: true
}
}
}
</script>
子组件的写法
<template>
<el-table-column
header-align="center"
align="center"
:key="'table1' + index"
:label="list.name">
<template slot-scope="scope">
<span v-html="scope.row[list.filed]"></span>
</template>
<template v-if="list.children && list.children.length !== 0">
<template v-for="(item1, index1) in list.children">
<table-child :list="item1" :key="'tabless' + index1"></table-child>
</template>
</template>
</el-table-column>
</template>
<script>
export default {
name: 'table-child',
props: {
list: Array
}
}
</script>
需要注意的是el-table标签和el-table-column之间不能嵌套其他标签,可用template否则渲染出来的列表第一列会跑到最后一列去
代码中的引用
传入组件的数据格式
tableData: {
thead: [
{filed: 'bigClass', name: '大类'},
{filed: 'detail', name: '细项'},
{
field: 'allDetail',
name: '详情',
children: [
{filed: 'weight', name: '权重'},
{filed: 'score', name: '得分'},
{filed: 'ranking', name: '排名'}
]
}
],
tbody: [
{bigClass: '收入<br/>(25%)', detail: '码号收入预算完成', ranking: 1, score: 0, weight: 25},
{bigClass: '宽带攻防<br/>(75%)', detail: '宽带新增', ranking: 1, score: 0, weight: 75},
{bigClass: '小计', detail: '小计', ranking: 1, score: 0, weight: 100},
{bigClass: '加扣分', detail: '客户经理、装维即时满意度测评', ranking: 1, score: 3, weight: 10},
{bigClass: '加扣分', detail: '小计', ranking: 1, score: 3, weight: 10},
{bigClass: '合计', detail: '合计', ranking: 1, score: 3, weight: 110}
],
columnFiled: 'bigClass', 需要合并的行,适合合并第一行(相同值必须放一起)
rowFiled: ['合计', '小计'] 需要合并的列名,适合合并前两列
},
引用
<array-table :tableData="tableData"></array-table>