使用element UI实现表格行/列合并

前言

本文代码使用vue2+element UI,通过给table传入span-method方法实现合并行或列

效果图

示例代码

后端返回数据格式如下

javascript 复制代码
{
  "total": 12,
  "records": [
    [
      {
        "id": 1,
        "project": "田径",
        "subitem": "100米",
        "category": "决赛",
        "score": 9.6,
        "creator": "张三",
        "competitionName": "国际田联锦标赛",
        "date": "2023-08-15",
        "location": "北京",
        "worldRecord": "1",
        "asiaRecord": "0"
      },
      {
        "id": 2,
        "project": "田径",
        "subitem": "100米",
        "category": "资格赛",
        "score": 10.1,
        "creator": "李四",
        "competitionName": "全国田径锦标赛",
        "date": "2023-09-01",
        "location": "上海",
        "worldRecord": "0",
        "asiaRecord": "0"
      }
    ],
    [
      {
        "id": 3,
        "project": "田径",
        "subitem": "200米",
        "category": "决赛",
        "score": 19.2,
        "creator": "王五",
        "competitionName": "国际田联锦标赛",
        "date": "2023-08-15",
        "location": "北京",
        "worldRecord": "1",
        "asiaRecord": "0"
      },
      {
        "id": 4,
        "project": "田径",
        "subitem": "200米",
        "category": "资格赛",
        "score": 20.5,
        "creator": "赵六",
        "competitionName": "全国田径锦标赛",
        "date": "2023-09-01",
        "location": "上海",
        "worldRecord": "0",
        "asiaRecord": "0"
      }
    ],
    [
      {
        "id": 15,
        "project": "田径",
        "subitem": "跳远",
        "category": "决赛",
        "score": 8.4,
        "creator": "马十三",
        "competitionName": "国际田联锦标赛",
        "date": "2023-08-15",
        "location": "北京",
        "worldRecord": "0",
        "asiaRecord": "1"
      },
      {
        "id": 16,
        "project": "田径",
        "subitem": "跳远",
        "category": "资格赛",
        "score": 7.8,
        "creator": "李十四",
        "competitionName": "全国田径锦标赛",
        "date": "2023-09-01",
        "location": "上海",
        "worldRecord": "0",
        "asiaRecord": "0"
      }
    ]
  ]
}

分析后端返回数据 :

records 是一个 二维数组,el-tabledata 属性通常期望的是 一维数组。

所以需要将records中的二维数组 扁平化为一维数组,再赋值。

代码如下

javascript 复制代码
<template>
  <div class="record-manage-container">
   
        <el-table :data="recordList" :span-method="mergeCells">
            <el-table-column prop="project" label="项目" width="180" />
            <el-table-column prop="subitem" label="小项" width="180"/>              
            <el-table-column prop="category" label="类别" />
            <el-table-column prop="score" label="成绩" />
            <el-table-column prop="creator" label="创造者" />
            <el-table-column prop="competitionName" label="比赛名称" />
            <el-table-column prop="date" label="日期" />
            <el-table-column prop="location" label="地点" />
            <el-table-column prop="worldRecord" label="世界纪录" />
            <el-table-column prop="asiaRecord" label="亚洲纪录" />
            
        </el-table>

  </div>
</template>

<script>
import { recordList } from "@/api/game/scoreManage";
export default {
  data() {
    return {
      recordList:[],

     
    };
  },
  created() {
    this.getRecordList()
  },
  methods: {
    // 获取纪录列表
    getRecordList() {
      // 在此处调用获取数据的接口
      recordList().then(res => {
        // console.log(res)
        // 扁平化 records 为一维数组
        this.recordList = res.records.flat()
        this.total = res.total
      })
    },

    mergeCells({ row, column, rowIndex, columnIndex }) {
      if (columnIndex === 0) {
        // 合并 "项目" 列
        const project = row.project;
        const prevProject = rowIndex > 0 ? this.recordList[rowIndex - 1].project : null;
        if (project === prevProject) {
          // 当前项目与上一行项目相同,隐藏当前单元格
          return [0, 0];
        } else {
          // 当前项目与上一行不同,计算合并行数
          const spanCount = this.recordList.filter(item => item.project === project).length;
          return [spanCount, 1]; // 合并 `spanCount` 行,列合并为 1
        }
      }

      if (columnIndex === 1) {
        // 合并 "小项" 列
        const subitem = row.subitem;
        const prevSubitem = rowIndex > 0 ? this.recordList[rowIndex - 1].subitem : null;
        if (subitem === prevSubitem) {
          return [0, 0];
        } else {
          const spanCount = this.recordList.filter(item => item.subitem === subitem).length;
          return [spanCount, 1];
        }
      }

      // 其他列不合并,返回默认值
      return [1, 1];
    },

    
  }
};
</script>

<style lang="scss" scoped>
.record-manage-container {
    padding: 20px;

    .title{
        font-size: 24px;
        font-weight: bold;
    }
}
</style>

分析

  1. res.records.flat():将 records 中的二维数组扁平化为一维数组。例如:
javascript 复制代码
const records = [
  [{ id: 1 }, { id: 2 }],
  [{ id: 3 }, { id: 4 }]
];
const flattened = records.flat();
console.log(flattened); // [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }]
  1. mergeCells()方法的实现逻辑

合并"项目"列 (columnIndex === 0)

  • 判断当前行与上一行的项目 (project) 是否相同。
  • 如果相同,返回 [0, 0],表示隐藏当前单元格,因为它会被上一个单元格合并。
  • 如果不同,则计算相同项目的行数 spanCount,返回 [spanCount, 1],表示合并 spanCount 行,列合并为 1。

合并"小项"列 (columnIndex === 1)

  • 判断当前行与上一行的小项 (subitem) 是否相同。
  • 如果相同,返回 [0, 0],隐藏当前单元格。
  • 如果不同,计算相同小项的行数 spanCount,返回 [spanCount, 1]

默认情况

  • 对于其他列(比如类别、成绩、创造者等),不需要进行合并,直接返回 [1, 1] 表示不合并。
相关推荐
海盐泡泡龟1 小时前
Javascript本地存储的方式有哪些?区别及应用场景?(含Deep Seek讲解)
开发语言·javascript·ecmascript
虚妄狼2 小时前
【Nuxt3】安装 Naive UI 按需自动引入组件
ui·vue
美狐美颜sdk2 小时前
从API到UI:直播美颜SDK中的滤镜与贴纸功能开发与落地方案详解
人工智能·ui·音视频·美颜sdk·视频美颜sdk·美颜api
帮帮志3 小时前
vue3与springboot交互-前后分离【验证element-ui输入的内容】
spring boot·后端·ui
计算机学姐3 小时前
基于SpringBoot的小型民营加油站管理系统
java·vue.js·spring boot·后端·mysql·spring·tomcat
Elastic 中国社区官方博客3 小时前
JavaScript 中使用 Elasticsearch 的正确方式,第一部分
大数据·开发语言·javascript·数据库·elasticsearch·搜索引擎·全文检索
万物得其道者成3 小时前
从零开始创建一个 Next.js 项目并实现一个 TodoList 示例
开发语言·javascript·ecmascript
子朔不言4 小时前
MH22D3开发高级UI应用,适配arm2d驱动
mcu·ui·arm2d·mh22d3·新龙微
sunbyte4 小时前
50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | Expanding Cards (展开式卡片)
javascript·vue.js·ecmascript
肠胃炎4 小时前
React Contxt详解
javascript·react.js·ecmascript