效果图如下
点击新增动物按钮,会新增一整行的数据 ,如果点击右侧操作按钮中的添加按钮,会添加一行小狗以右的数据,而小狗以前的数据和第一行数据合并一行。
<template>
<div>
<div style="magin-bottom: 20px; text-align: left">
<el-row>
<el-col :span="24">
<el-button class="myBtn" @click="addDongWu()" type="primary"
>新增动物</el-button
>
</el-col>
</el-row>
</div>
<el-table :data="tableData" :span-method="spanMethod" style="width: 100%">
<el-table-column prop="leftKey" label="动物">
<template slot-scope="scope">
<el-input v-model="scope.row.dongwu"></el-input>
</template>
</el-table-column>
<el-table-column prop="leftKey" label="日期">
<template slot-scope="scope">
<!-- <div>{
{ scope.row.date }}</div> -->
<el-input v-model="scope.row.date"></el-input>
</template>
</el-table-column>
<el-table-column prop="leftKey" label="姓名">
<template slot-scope="scope">
<el-input v-model="scope.row.name"></el-input>
</template>
</el-table-column>
<el-table-column prop="leftKey" label="年龄">
<template slot-scope="scope">
<el-input v-model="scope.row.age"></el-input>
</template>
</el-table-column>
<el-table-column prop="xiaogou" label="小狗">
<template slot-scope="scope">
<el-input v-model="scope.row.xiaogou"></el-input>
</template>
</el-table-column>
<el-table-column prop="xiaomao" label="小猫">
<template slot-scope="scope">
<el-input v-model="scope.row.xiaomao"></el-input>
</template>
</el-table-column>
<el-table-column prop="xiaoya" label="小鸭">
<template slot-scope="scope">
<el-input v-model="scope.row.xiaoya"></el-input>
</template>
</el-table-column>
<el-table-column prop="oprate" label="操作">
<template slot-scope="scope">
<button @click="addXiaoGou(scope.row)">添加</button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
components: {},
data () {
return {
tableData: [],
spanProps: ['leftKey'], // 需要合并行的字段
};
},
methods: {
addDongWu () { // 新增一行动物
// 自定义一个字段叫leftKey,用来作为合并的标识
const data = [{ dongwu: '', date: '', name: '', age: '', xiaogou: '', xiaomao: '', xiaoya: '', leftKey: `dongwu${this.tableData.length + 1}` }]; // 新增一条数据
let newData = [...this.tableData, ...data];
newData = newData.map((item, index) => { return { ...item, rowIndex: index } }); // 给每一行添加rowIndex字段
this.tableData = [...newData];
},
addXiaoGou (row) { // 新增一行小狗
// leftKey:row.leftKey这句代码的意思是点击这个新增按钮时leftKey是取上一行的leftKey,leftKey的值相同就合并
const data = { dongwu: '', date: '', name: '', age: '', xiaogou: '', xiaomao: '', xiaoya: '', leftKey: row.leftKey }; // 新增一条数据
this.tableData.splice(row.rowIndex + 1, 0, data) // 向数组指定位置插入一条数据
this.tableData = this.tableData.map((item, index) => { return { ...item, rowIndex: index } }); // 给每一行添加rowIndex字段
console.log('this.tableData', this.tableData);
},
// 合并行
//参数:dataSource-表格数据,spanProps-需要进行合并计算的字段列表,rowIndex-当前行数,columnIndex-当前列数,column-当前列
spanMethodFunc (dataSource = [], spanProps = [], rowIndex, columnIndex, column) {
// if (columnIndex >= spanProps.length || !spanProps[columnIndex]) {
if (!spanProps.includes(column.property)) {
// 根据传入的字段列表,判断不需要合并的列
return [1, 1];
} else {
//使用try-catch,如果方法错误返回错误信息
try {
// let _spanProps = spanProps.slice(columnIndex, columnIndex + 1); //截取需要用到判断的字段名
// 过滤出需要合并的当前列字段
let _spanProps = spanProps.filter(item => item == column.property);
// 判断是否从本行开始合并
let merge = _spanProps.some((item) => {
// 如果当前行所需要判断合并的字段中有一个跟前一条数据不一样,本条数据即为合并的起点,第一条数据直接为合并起点
return rowIndex == 0 || (item && dataSource[rowIndex][item] != dataSource[rowIndex - 1][item]);
});
// 如果本条数据是合并起点,获取需要合并的数据条数
if (merge) {
let _list = dataSource.slice(rowIndex); //截取从本条数据开始的列表
// 获取合并行数
let _lineNum = _list.findIndex((item, index) => {
//同merge判断,找到合并的终点
return (
index &&
_spanProps.some((item1) => {
return item1 && item[item1] != _list[0][item1];
})
);
});
// 合并行数为-1时,输出_list的长度,否则输出_lineNum
return [_lineNum === -1 ? _list.length : _lineNum, 1];
} else {
// 否则,返回[0,0],即本条数据被合并
return [0, 0];
}
} catch (err) {
console.error("spanMethodFunc error:", err);
}
}
},
// 合并行
spanMethod ({ row, column, rowIndex, columnIndex }) {
return !this.spanProps ||
this.spanProps.length === 0 ? false : this.spanMethodFunc(this.tableData, this.spanProps, rowIndex, columnIndex, column)
},
},
mounted () {
}
};
</script>
<style scoped>
</style>