【vue + element】el-table支持多层级合并列

可直接使用,按照配置,支持多层级合并行

文章目录

页面使用

在需要调用的页面使用:

html 复制代码
<el-table v-loading="loading" :data="tableList" height="500px" style="width: 100%" border
          :span-method="handleSpanMethod">
    ...
javascript 复制代码
import mergeCellsMixin from '@/mixins/mergeCellsMixin'

mixins: [mergeCellsMixin],
method:{
 getList() {
      console.log('getList', this.form)
      this.tableList = [{
        id: '12987122',
        demandNo: '12347214823',
        deliveryLocation: '送货地点1',
        applicant: '申请人1',
        costCenter: '王小虎',
        amount1: '234',
        amount2: '3.2',
        amount3: 10
      }, {
        id: '12987123',
        demandNo: '12347214823',
        deliveryLocation: '送货地点1',
        applicant: '申请人1',
        costCenter: '王小虎',
        amount1: '165',
        amount2: '4.43',
        amount3: 12
      }, {
        id: '12987124',
        demandNo: '12347214823',
        deliveryLocation: '送货地点2',
        applicant: '申请人1',
        costCenter: '王小虎',
        amount1: '324',
        amount2: '1.9',
        amount3: 9
      }, {
        id: '12987125',
        demandNo: '12347214823',
        deliveryLocation: '送货地点2',
        applicant: '申请人1',
        costCenter: '王小虎',
        amount1: '621',
        amount2: '2.2',
        amount3: 17
      }, {
        id: '12987126',
        demandNo: '12347214823',
        deliveryLocation: '送货地点2',
        applicant: '申请人2',
        costCenter: '王小虎',
        amount1: '539',
        amount2: '4.1',
        amount3: 15
      }, {
        id: '12987126',
        demandNo: '123472148000',
        deliveryLocation: '送货地点2',
        applicant: '申请人2',
        costCenter: '王小虎',
        amount1: '539',
        amount2: '4.1',
        amount3: 15
      }]
      this.getSpanArr()
    },
    // 获取合并数组
    getSpanArr() {
      // key: 当前字段名 dependsOn: 当前字段依赖哪些前面字段
      this.mergeRules = [
        { key: 'demandNo', dependsOn: [] },
        { key: 'deliveryLocation', dependsOn: ['demandNo'] },
        { key: 'applicant', dependsOn: ['demandNo', 'deliveryLocation'] },
        { key: 'costCenter', dependsOn: ['demandNo', 'deliveryLocation', 'applicant'] }
      ]
      this.spanArr = this.createSpanArr(this.tableList, this.mergeRules)
    },
    // 合并单元格
    handleSpanMethod({ row, column, rowIndex, columnIndex }) {
      // 获取对应的合并数组
      const spanMap = {
        0: this.spanArr.demandNo, // 需求单合并
        1: this.spanArr.deliveryLocation, // 送货地点合并
        2: this.spanArr.applicant, // 申请人合并
        3: this.spanArr.costCenter // 成本中心合并
      };
      return this.mergeCells(spanMap, { row, column, rowIndex, columnIndex })
    },
}

mergeCellsMixin.js

javascript 复制代码
export default {
    data() {
        return {

        }
    },
    methods: {
        /**
         * @description 创建合并数组
         * @param {Array} tableList 表格数据
         * @param {Array} mergeRules 合并规则 ({key: 当前字段名 dependsOn: 当前字段依赖哪些前面字段})
         * @example  tableList = [
         {demandNo: '', deliveryLocation: '',applicant: '',costCenter: '',materialName:''}]
         * @example mergeRules = [
         { key: 'demandNo', dependsOn: [] },
         { key: 'deliveryLocation', dependsOn: ['demandNo'] },
         { key: 'applicant', dependsOn: ['demandNo', 'deliveryLocation'] },
         { key: 'costCenter', dependsOn: ['demandNo', 'deliveryLocation', 'applicant'] }]
         * */
        createSpanArr(tableList, mergeRules) {
            // 存放每个字段对应的合并数组
            const spanArr = {}
            // 记录每个字段当前合并块的起始索引位置
            const posMap = {}
            // 最终返回值
            const result = {}
            // 初始化每个字段的数组
            mergeRules.forEach(rule => {
                spanArr[rule.key] = [];
                result[rule.key] = spanArr[rule.key];
                posMap[rule.key] = 0;
            });

            for (let i = 0; i < tableList.length; i++) {
                if (i === 0) {
                    mergeRules.forEach(rule => {
                        // 所有字段在第一行都开启新块,设为 1
                        spanArr[rule.key].push(1)
                        // 当前字段从第 0 行开始合并
                        posMap[rule.key] = 0
                    });
                } else {
                    // 当前行
                    const curr = tableList[i]
                    // 上一行
                    const prev = tableList[i - 1]
                    for (const rule of mergeRules) {
                        // key: 当前字段名 dependsOn: 当前字段依赖哪些前面字段
                        const { key, dependsOn } = rule
                        // 检查依赖字段是否一致
                        const depsMatch = dependsOn.every(dep => curr[dep] === prev[dep])
                        if (!depsMatch) {
                            // 如果依赖不一致,则当前字段开启新块,并重置后续字段
                            spanArr[key].push(1);
                            posMap[key] = i;
                            // 后续字段都设为新块
                            const index = mergeRules.indexOf(rule);
                            for (let j = index + 1; j < mergeRules.length; j++) {
                                const nextKey = mergeRules[j].key;
                                spanArr[nextKey].push(1);
                                posMap[nextKey] = i;
                            }
                            break;
                        } else {
                            // 当前字段值一致时继续合并
                            if (curr[key] === prev[key]) {
                                // 当前字段值一致时,行数加 1
                                spanArr[key][posMap[key]] += 1;
                                // 当前行标记为被合并
                                spanArr[key].push(0);
                            } else {
                                // 否则开启新块
                                spanArr[key].push(1);
                                // 更新当前字段的起始行号
                                posMap[key] = i;
                            }
                        }
                    }
                }
            }
            return result;
        },
        /**
         * @description 合并单元格
         * @param {Object} spanMap 创建的合并数组
         * @param {} row 当前行
         * @param {} column 当前列
         * @param {} rowIndex 当前行索引
         * @param {} columnIndex 当前列索引
         * @example spanMap = {
            0: this.spanArr.demandNo,
            1: this.spanArr.deliveryLocation,
            2: this.spanArr.applicant,
            3: this.spanArr.costCenter }
         * */
        mergeCells(spanMap, { row, column, rowIndex, columnIndex }) {
            // 获取对应的 spanArr
            const spanArr = spanMap[columnIndex];
            if (spanArr) {
                const r = spanArr[rowIndex];
                const c = spanArr[rowIndex] > 0 ? 1 : 0;
                return [r, c];
            }
            return [1, 1]; // 默认不合并
        }
    }
}
相关推荐
独立开阀者_FwtCoder几秒前
Nginx 通过匹配 Cookie 将请求定向到特定服务器
java·vue.js·后端
哒哒哒52852024 分钟前
HTTP缓存
前端·面试
T___27 分钟前
从入门到放弃?带你重新认识 Headless UI
前端·设计模式
wordbaby28 分钟前
React Router 中调用 Actions 的三种方式详解
前端·react.js
黄丽萍34 分钟前
前端Vue3项目代码开发规范
前端
葬送的代码人生36 分钟前
AI Coding→像素飞机大冒险:一个让你又爱又恨的小游戏
javascript·设计模式·ai编程
curdcv_po38 分钟前
🏄公司报销,培养我成一名 WebGL 工程师⛵️
前端
Jolyne_1 小时前
前端常用的树处理方法总结
前端·算法·面试
wordbaby1 小时前
后端的力量,前端的体验:React Router Server Action 的魔力
前端·react.js
Alang1 小时前
Mac Mini M4 16G 内存本地大模型性能横评:9 款模型实测对比
前端·llm·aigc