效果如下:
image.png
image.png
版本信息如下:
"vue": "^2.5.2", "element-ui": "^2.7.2",
代码如下:
<!--表格行合并-->
<template>
<div style="margin: 20px">
<div style="margin: 20px 0;text-align: right;">
<el-button type="primary" @click="logTableData">打印表格数据</el-button>
</div>
<el-table
v-loading="tableLoading"
:data="tableData"
:span-method="spanMethod"
:header-row-style="headerRowStyle"
style="width: 100%">
<el-table-column
align="center"
v-for="(col,colIndex) in tableHeader"
:key="`col-${colIndex}`"
:prop="col.prop"
:min-width="col.width || 80"
:label="col.label">
<template slot-scope="{row, $index}">
<el-input v-if="!col.noEdit && row._edit" class="inputNumber" :placeholder="`请输入${col.label}`"
v-model="row[col.prop]"/>
<span v-else>{{ row[col.prop] }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="配比">
<el-table-column label="" align="center" v-for="rateColIndex in maxTableColLength" :key="`rate-${rateColIndex}`"
:min-width="80">
<template slot-scope="{row, $index}">
<!-- 第一行-->
<template v-if="row.rowSpan">
<span v-if="rateColIndex <= row.list.length">{{ row.list[rateColIndex - 1].name }}</span>
</template>
<!-- 第二行,操作的也是上一行的数据-->
<!-- 有这项的才可编辑-->
<template v-else-if="rateColIndex <= tableData[$index-1].list.length">
<el-input class="inputNumber" type="number" v-if="tableData[$index-1]._edit" placeholder="请输入"
v-model="tableData[$index-1].list[rateColIndex-1].rate"/>
<span v-else>{{ valFixed(tableData[$index-1].list[rateColIndex - 1].rate, 2) }}</span>
</template>
</template>
</el-table-column>
</el-table-column>
<el-table-column
fixed="right"
align="center"
label="操作"
width="120">
<template slot-scope="{row,$index}">
<template v-if="!row._edit">
<el-button @click="rowEdit(row, $index)" type="text">修改</el-button>
</template>
<template v-else>
<el-button @click="rowSave(row, $index)" type="text">保存</el-button>
<el-button @click="rowCancel(row, $index)" type="text">取消</el-button>
</template>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
data() {
return {
tableLoading: false,
tableHeader: [
{
prop: 'pileNo',
label: '堆号',
noEdit: true
},
{
prop: 'tfe',
label: '品位'
},
{
prop: 'ironWeight',
label: '铁水产量'
}
],
tableData: [],
historyRow: null, // 行编辑时存储历史数据
}
},
computed: {
// 表格中最大配比列长度
maxTableColLength() {
let arr = this.tableData.map(item => {
return (item.list || []).length
})
return arr.length ? Math.max(...arr) : 0
},
},
created() {
this.initData()
},
methods: {
// 判断值是否为空
isNull(val) {
return val === null || val === void 0 || val === '' || (val).toString() === 'NaN'
},
/**
* 值保留小数处理
* @val: 需要保留小数的值
* @fixed:小数位数
* @dt:为空时的默认值
* @unit:单位
* */
valFixed(val, fixed = 3, dt = '', unit = '') {
return this.isNull(val) ? dt : (parseFloat(val).toFixed(fixed) + unit)
},
initData() {
// 模拟数据
let data = [
{
pileNo: '11111111',
tfe: 56.2,
ironWeight: 5000,
list: [
{
name: '精粉1',
rate: 10,
},
{
name: '精粉2',
rate: 5,
},
{
name: '混合粉2',
rate: 8,
},
{
name: '混合粉4',
rate: 3,
}
],
},
{
pileNo: '22222222',
tfe: 50.34,
ironWeight: 5500,
list: [
{
name: '精粉5',
rate: 10,
},
{
name: '混合粉1',
rate: 8,
},
{
name: '混合粉2',
rate: 3,
}
],
},
{
pileNo: '33333333',
tfe: 49,
ironWeight: 4900,
list: [
{
name: '精粉5',
rate: 5,
},
{
name: '混合粉1',
rate: 10,
},
{
name: '混合粉2',
rate: 20,
},
{
name: '混合粉3',
rate: 20,
}
],
}
]
let tableData = []
data.map(item => {
let list = item.list || []
tableData = tableData.concat([
{
...item,
// 辅助变量
rowSpan: 2
},
{}
])
})
this.tableData = tableData
},
// 表头隐藏
headerRowStyle({row, rowIndex}) {
if (rowIndex === 1) {
return {'display': 'none'}
}
},
// 表格行合并
spanMethod({row, column, rowIndex, columnIndex}) {
let startColIndex = this.tableHeader.length // 数的,第五列开始是配比列
let endColIndex = startColIndex + (this.maxTableColLength - 1)
let isRateCol = columnIndex >= startColIndex && columnIndex <= endColIndex // 配比列不进行行合并
if (row.rowSpan) { // name行
if (!isRateCol) {
return [row.rowSpan, 1]
} else {
return [1, 1]
}
} else { // 配比行
if (!isRateCol) {
return [0, 1]
} else {
return [1, 1]
}
}
},
// 打印数据
logTableData() {
let data = this.tableData.filter(item => item.rowSpan)
data.map((item) => {
let str = ''
this.tableHeader.map(sub => {
str += `${sub.label}: ${item[sub.prop]} `
})
item.list.map(sub => {
str += `${sub.name}: ${sub.rate} `
})
console.log(`%c${str}`, 'color: #43bb88;font-weight: bold;');
})
console.log('最终数据为:', data)
},
// 行编辑 --------------- start
// 修改
rowEdit(row, rowIndex) {
// console.log(row, rowIndex)
if (this.tableData.find(item => item._edit)) return this.$message({
message: '请保存正在编辑的行',
type: 'warning'
});
let editRow = row
this.historyRow = JSON.parse(JSON.stringify(editRow))
this.$set(editRow, '_edit', true)
},
// 保存正在编辑的
rowSave(row, rowIndex) {
// console.log(row, rowIndex)
this.historyRow = {}
row._edit = false
},
// 取消保存
rowCancel(row, rowIndex) {
// console.log(row, rowIndex)
this.tableData.splice(rowIndex, 1, {
...this.historyRow,
_edit: false
})
this.historyRow = {}
}
// 行编辑 --------------- end
}
}
</script>
<style scoped lang="less">
.inputNumber {
/deep/ input::-webkit-outer-spin-button,
/deep/ input::-webkit-inner-spin-button {
-webkit-appearance: none !important;
}
/deep/ input[type='number'] {
-moz-appearance: textfield;
}
}
</style>
大体思路
image.png1.表头其实有两行,下面这行被隐藏了。
2.表格中每行数据是两行,表格行合并了,第二行是空行,编辑时操作的是第一行的数据。
3.这里使用行合并是为了让配比列表格宽度自适应。
若对你有帮助,请点个赞吧,谢谢支持!
本文地址:https://www.jianshu.com/p/0fdfbb68a73e?v=1668668903593,转载请注明出处,谢谢。
网友评论