做一个动态合并的table表格, 如下图

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一样使用
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐