做一个动态合并的table表格, 如下图
![](https://img-blog.csdnimg.cn/direct/8b9b6e00aba04a14baeee619e82a843f.png)
![](https://img-blog.csdnimg.cn/direct/136b8c7a18cd40bfb4d0ffbed5f1644c.png)
![](https://img-blog.csdnimg.cn/direct/9c007bfb66554e77b0ac1675e3ddf4e5.png)
1.首先定义需要合并的字段及合并后的对象
data(){
return {
mergeFields: ['name', 'amount3'],
mergeObj: {}
}
}
2.分配合并项函数, data为数据源
//获取合并序号
getSpanArr(data = []) {
this.mergeFields.forEach(key => {
// 用来记录合并行的起始位置
let count = 0
// 记录每一列的合并信息
this.mergeObj[key] = []
data.forEach((item, index) => {
// 第一行直接 push 一个 1
if (!index) {
this.mergeObj[key].push(1)
return
}
// 判断当前行是否与上一行其值相等
// 如果相等在count记录的位置其值+1
// 表示当前行需要合并 并添加一个 0 占位
if (item[key] === data[index - 1][key]) {
this.mergeObj[key][count] += 1
this.mergeObj[key].push(0)
return
}
// 如果当前行和上一行其值不相等 记录当前位置
count = index
// 重新push一个1
this.mergeObj[key].push(1)
})
})
},
//合并行
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
if (!this.mergeFields.includes(column.property)) return
// 判断其值是不是为0
if (this.mergeObj[column.property][rowIndex]) {
return [this.mergeObj[column.property][rowIndex], 1]
}
// 如果为0则为需要合并的行
return [0, 0]
},
3.数据内容改变时函数
//改变百分比触发
changeVal(val, row, idx) {
//找到一级相同项
let alikeList = this.tableData.filter(it => it.name == row.name)
//汇总
let allPercent = alikeList.reduce((acc, curr) => {
return acc + curr.amount2
}, 0)
//改变每一项
let list = JSON.parse(JSON.stringify(this.tableData))
list.forEach(it => {
if (it.name == row.name) {
it.amount3 = allPercent
}
})
//先分配需要合并项
this.getSpanArr(list)
this.$nextTick(() => {
this.tableData = JSON.parse(JSON.stringify(list))
})
}
4.完整代码
<template>
<div class="wokeRate">
<el-table :data="tableData" :span-method="objectSpanMethod" :border="true" size="small">
<el-table-column v-for="item in fields" :key="item.key" :prop="item.key" :label="item.label"
:width="item.width">
<template slot-scope="scope">
<div class="it" v-if="item.type == 'text'">{{ scope.row[item.key] }}</div>
<div class="it" v-if="item.type == 'input'">
<el-input-number size="mini" v-model="scope.row[item.key]" :placeholder="`请输入${item.label}`"
@change="e => changeVal(e, scope.row, scope.$index)"></el-input-number>
</div>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: 'DfcvDtmsVueWokeRate',
data() {
return {
mergeFields: ['name', 'amount3'],
mergeObj: {},
tableData: [
{
name: '维保',
amount1: '维保',
amount2: 0,
amount3: 0
}, {
name: '等待样品',
amount1: '等待样机',
amount2: 0,
amount3: 0
}, {
name: '等待样品',
amount1: '等待样件',
amount2: 0,
amount3: 0
},
{
name: '无任务',
amount1: '无任务',
amount2: 0,
amount3: 0
}
],
fields: [
{
label: '一级',
key: 'name',
type: 'text'
},
{
label: '二级',
key: 'amount1',
type: 'text'
},
{
label: '百分比(%)',
key: 'amount2',
type: 'input'
},
{
label: '汇总(%)',
key: 'amount3',
type: 'text'
}
]
}
},
mounted() {
this.getSpanArr(this.tableData)
},
methods: {
//获取合并序号
getSpanArr(data = []) {
this.mergeFields.forEach(key => {
// 用来记录需要合并行的起始位置
let count = 0
// 记录每一列的合并信息
this.mergeObj[key] = []
data.forEach((item, index) => {
// 第一行直接 push 一个 1
if (!index) {
this.mergeObj[key].push(1)
return
}
// 判断当前行是否与上一行其值相等
// 如果相等在count记录的位置其值+1
// 表示当前行需要合并 并添加一个 0 占位
if (item[key] === data[index - 1][key]) {
this.mergeObj[key][count] += 1
this.mergeObj[key].push(0)
return
}
// 如果当前行和上一行其值不相等 记录当前位置
count = index
// 重新push一个 1
this.mergeObj[key].push(1)
})
})
},
//合并行
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
if (!this.mergeFields.includes(column.property)) return
// 判断其值是不是为0
if (this.mergeObj[column.property][rowIndex]) {
return [this.mergeObj[column.property][rowIndex], 1]
}
// 如果为0则为需要合并的行
return [0, 0]
},
//改变百分比触发
changeVal(val, row, idx) {
//找到一级相同项
let alikeList = this.tableData.filter(it => it.name == row.name)
//汇总
let allPercent = alikeList.reduce((acc, curr) => {
return acc + curr.amount2
}, 0)
//改变每一项
let list = JSON.parse(JSON.stringify(this.tableData))
list.forEach(it => {
if (it.name == row.name) {
it.amount3 = allPercent
}
})
//先分配需要合并项
this.getSpanArr(list)
this.$nextTick(() => {
this.tableData = JSON.parse(JSON.stringify(list))
})
}
}
}
</script>
<style lang="scss" scoped>
.wokeRate {
width: 100%;
padding: 20px 0;
.el-table {
margin-top: 20px;
}
}
</style>
elementPlus一样使用