表格单元行合并方法

记录一下实际开发时候所用到的表格单元行合并方法。

问题描述

使用 el-table 表格时候在某几列需要实现上下合并单元行,比如表头是电厂,机组,还有一些机组的配置,电厂包含多个机组,机组包含多个配置,此时电厂和机组就需要合并单元行。

原先表格展示如下:

可以看到一个电厂下有很多个机组,一个机组下有多个配置,所以电厂和机组都需要去进行合并单元行。

合并电厂单元行

先去创建一个电厂的数组,和一个电厂的索引。

js 复制代码
  data() {
    return {
      // 表格数据
      tableData: [...],
      // 电厂数组
      spanArr_plant: [],
      // 电厂索引
      pos_plant: 0,
    };
  },

处理数据的方法:

js 复制代码
// 初始化电厂数组和电厂索引数据
this.spanArr_plant = [];
this.pos_plant = 0;
for (let i = 0; i < this.tableData.length; i++) {
  if (i === 0) {
    // 此时电厂数组为[1],表示当前电厂有一行数据
    this.spanArr_plant.push(1);
    // 此时电厂索引为0,表示的就是[1]中当前电厂所在索引
    this.pos_plant = 0;
  } else {
    // 判断当前行数据中电厂信息与上一行数组电厂信息是否相同
    if (this.tableData[i]["plant"] === this.tableData[i - 1]["plant"]) {
      // 如果相同,电厂数组里的电厂索引位置+1,表示电厂相同的数据多了一行
      this.spanArr_plant[this.pos_plant] += 1;
      // 电厂数组再push一个0
      this.spanArr_plant.push(0);
      // 此时电厂数组就是[2,0],表示的就是电厂相同的数据目前有两行,如果下一项还相同的话,就是[3,0,0]
    } else {
      // 如果下一行数据的电厂信息和上一行数据电厂信息不相同,电厂数据就重新push一个1,代表有新的电厂,然后电厂索引也改为这个新电厂在电厂数组的索引
      this.spanArr_plant.push(1);
      this.pos_plant = i;
    }
  }
}

然后就是el-table自带的合并单元行的方法:

html 复制代码
    <el-table
      :data="tableData"
      border
      stripe
      height="100%"
      :cell-style="{ textAlign: 'center' }"
      :header-cell-style="{ textAlign: 'center' }"
      :span-method="objectSpanMethod"
    >
      <el-table-column label="电厂" prop="plant"></el-table-column>
      <el-table-column label="机组" prop="unit"></el-table-column>
      <el-table-column label="配置" prop="configuration"></el-table-column>
    </el-table>
js 复制代码
    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
      // 电厂是第一列,所以判断columnIndex === 0
      if (columnIndex === 0) {
        const _row = this.spanArr_plant[rowIndex];
        const _col = _row > 0 ? 1 : 0;
        return [_row, _col];
      }
    },

效果展示:

合并电厂单元行和机组单元行

这里不能光合并一个电厂的单元行,还有机组的单元行,但是这里注意一下,这里不是说跟合并电厂单元行一样再重复一遍机组的就好了,这里的机组合并的前提是电厂也得一样。

首先还是先创建一个机组数据和机组索引:

js 复制代码
  data() {
    return {
      // 表格数据
      tableData: [...],
      // 电厂数组
      spanArr_plant: [],
      // 电厂索引
      pos_plant: 0,
      // 机组数组
      spanArr_unit: [],
      // 机组索引
      pos_unit: 0,
    };
  },

处理数据的方法:

js 复制代码
// 初始化数组和索引数据
this.spanArr_plant = [];
this.pos_plant = 0;
this.spanArr_unit = [];
this.pos_unit = 0;
for (let i = 0; i < this.tableData.length; i++) {
  if (i === 0) {
    this.spanArr_plant.push(1);
    this.pos_plant = 0;
    // 跟电厂一样的操作
    this.spanArr_unit.push(1);
    this.pos_unit = 0;
  } else {
    if (this.tableData[i]["plant"] === this.tableData[i - 1]["plant"]) {
      this.spanArr_plant[this.pos_plant] += 1;
      this.spanArr_plant.push(0);

      // 在电厂相同的时候进行跟电厂一样的判断
      if (this.tableData[i]["unit"] === this.tableData[i - 1]["unit"]) {
        this.spanArr_unit[this.pos_unit] += 1;
        this.spanArr_unit.push(0);
      } else {
        this.spanArr_unit.push(1);
        this.pos_unit = i;
      }
    } else {
      this.spanArr_plant.push(1);
      this.pos_plant = i;
      // 电厂不相同的时候也是进行跟电厂一样的操作
      this.spanArr_unit.push(1);
      this.pos_unit = i;
    }
  }
}

然后就是el-table自带的合并单元行的方法:

html 复制代码
    <el-table
      :data="tableData"
      border
      stripe
      height="100%"
      :cell-style="{ textAlign: 'center' }"
      :header-cell-style="{ textAlign: 'center' }"
      :span-method="objectSpanMethod"
    >
      <el-table-column label="电厂" prop="plant"></el-table-column>
      <el-table-column label="机组" prop="unit"></el-table-column>
      <el-table-column label="配置" prop="configuration"></el-table-column>
    </el-table>
js 复制代码
    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
      if (columnIndex === 0) {
        const _row = this.spanArr_plant[rowIndex];
        const _col = _row > 0 ? 1 : 0;
        return [_row, _col];
      }
      // 机组为第二列所以判断columnIndex === 1
      if (columnIndex === 1) {
        const _row = this.spanArr_unit[rowIndex];
        const _col = _row > 0 ? 1 : 0;
        return [_row, _col];
      }
    }

全部代码如下:

html 复制代码
<template>
  <div class="screen-view">
    <el-table
      :data="tableData"
      border
      stripe
      height="100%"
      :cell-style="{ textAlign: 'center' }"
      :header-cell-style="{ textAlign: 'center' }"
      :span-method="objectSpanMethod"
    >
      <el-table-column label="电厂" prop="plant"></el-table-column>
      <el-table-column label="机组" prop="unit"></el-table-column>
      <el-table-column label="配置" prop="configuration"></el-table-column>
    </el-table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      tableData: [
        {
          plant: "电厂1",
          unit: "机组1",
          configuration: "配置1",
        },
        {
          plant: "电厂1",
          unit: "机组1",
          configuration: "配置2",
        },
        {
          plant: "电厂1",
          unit: "机组1",
          configuration: "配置3",
        },
        {
          plant: "电厂1",
          unit: "机组2",
          configuration: "配置1",
        },
        {
          plant: "电厂1",
          unit: "机组2",
          configuration: "配置2",
        },
        {
          plant: "电厂2",
          unit: "机组1",
          configuration: "配置1",
        },
        {
          plant: "电厂2",
          unit: "机组1",
          configuration: "配置2",
        },
        {
          plant: "电厂2",
          unit: "机组2",
          configuration: "配置1",
        },
        {
          plant: "电厂2",
          unit: "机组2",
          configuration: "配置2",
        },
        {
          plant: "电厂2",
          unit: "机组2",
          configuration: "配置3",
        },
      ],
      // 电厂数组
      spanArr_plant: [],
      // 电厂索引
      pos_plant: 0,
      // 机组数组
      spanArr_unit: [],
      // 机组索引
      pos_unit: 0,
    };
  },
  created() {
    this.init();
  },
  methods: {
    init() {
      this.spanArr_plant = [];
      this.pos_plant = 0;
      this.spanArr_unit = [];
      this.pos_unit = 0;
      for (let i = 0; i < this.tableData.length; i++) {
        if (i === 0) {
          this.spanArr_plant.push(1);
          this.pos_plant = 0;
          this.spanArr_unit.push(1);
          this.pos_unit = 0;
        } else {
          if (this.tableData[i]["plant"] === this.tableData[i - 1]["plant"]) {
            this.spanArr_plant[this.pos_plant] += 1;
            this.spanArr_plant.push(0);

            if (this.tableData[i]["unit"] === this.tableData[i - 1]["unit"]) {
              this.spanArr_unit[this.pos_unit] += 1;
              this.spanArr_unit.push(0);
            } else {
              this.spanArr_unit.push(1);
              this.pos_unit = i;
            }
          } else {
            this.spanArr_plant.push(1);
            this.pos_plant = i;
            this.spanArr_unit.push(1);
            this.pos_unit = i;
          }
        }
      }
    },
    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
      if (columnIndex === 0) {
        const _row = this.spanArr_plant[rowIndex];
        const _col = _row > 0 ? 1 : 0;
        return [_row, _col];
      }
      if (columnIndex === 1) {
        const _row = this.spanArr_unit[rowIndex];
        const _col = _row > 0 ? 1 : 0;
        return [_row, _col];
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.screen-view {
  box-sizing: border-box;
  padding: 10px;
  height: 100%;
}
</style>

效果展示如下:

相关推荐
前端大卫1 小时前
Vue3 + Element-Plus 自定义虚拟表格滚动实现方案【附源码】
前端
却尘2 小时前
Next.js 请求最佳实践 - vercel 2026一月发布指南
前端·react.js·next.js
ccnocare2 小时前
浅浅看一下设计模式
前端
Lee川2 小时前
🎬 从标签到屏幕:揭秘现代网页构建与适配之道
前端·面试
Ticnix2 小时前
ECharts初始化、销毁、resize 适配组件封装(含完整封装代码)
前端·echarts
纯爱掌门人2 小时前
终焉轮回里,藏着 AI 与人类的答案
前端·人工智能·aigc
twl2 小时前
OpenClaw 深度技术解析
前端
崔庆才丨静觅2 小时前
比官方便宜一半以上!Grok API 申请及使用
前端
星光不问赶路人2 小时前
vue3使用jsx语法详解
前端·vue.js
天蓝色的鱼鱼2 小时前
shadcn/ui,给你一个真正可控的UI组件库
前端