element plus 根据嵌套数据合并表格

介绍

因为最近项目中遇到合并表格行的需求,所以用这篇文章记录下实现思路。

看下实现效果:

实现逻辑

element plus 实现 table 的合并行或者列需要实现 span-method 方法。 官网地址element-plus-table

案例中的代码是实现行的合并,假设接口返回的数据是嵌套的模式,父级就是需要合并的列表,内层的数据长度就是需要合并的行数。当然如果嵌套的层次比较深,就需要遍历内层的数量统计最外层需要合并的数量。

案例代码是三层的结构,使用简单的嵌套循环,一般项目中也够用了,更多层级的数据结构也是一样的道理,多加n 次循环,此时建议使用递归来实现了。

代码实现

vue 复制代码
<script setup>
import { ref } from "vue";

// 模拟数据
const testData = [
  {
    fromMajorCity: 'BFN',
    data: [
      {
        level: 1,
        toMajorCity: 'BFN,CPT',
        data: [
          {
            weightGt: 0,
            weightLte: 15,
            basic_weight: 5,
            starting_price: 10,
            thereafter_price: 4,
            per_nkg: 1
          },
          {
            weightGt: 15,
            weightLte: null,
            basic_weight: 5,
            starting_price: 9.5,
            thereafter_price: 4,
            per_nkg: 1
          }
        ]
      },
      {
        level: 2,
        toMajorCity: 'DUR,ELS,KIM,WLK.Other',
        data: [
          {
            weightGt: 0,
            weightLte: null,
            basic_weight: 5,
            starting_price: 10,
            thereafter_price: 5,
            per_nkg: 1
          }
        ]
      }
    ]
  }
]

// 扁平化数据并且计算合并行的 rowspan
const flattenDataWithRowspan = (nestData) => {
  const flatData = []

  nestData.forEach((row) => {
    let firstRowSpan = 0 // 最外层合并行数
    row.data?.forEach((item) => {  
      const secondRowSpan = item.data.length // 第二层合并行数
      item.secondRowSpan = secondRowSpan
      firstRowSpan += secondRowSpan
    })
    row.firstRowSpan = firstRowSpan
  })
  
  nestData.forEach((row) => {
    row.data?.forEach((item, i) => {
      item.data?.forEach((val, index) => {
        flatData.push({
          fromMajorCity: row.fromMajorCity,
          level: item.level,
          toMajorCity: item.toMajorCity,
          ...val,
          firstRowSpan: (index === 0 && i == 0) ? row.firstRowSpan : 0,
          secondRowSpan: index === 0 ? item.secondRowSpan : 0,
        })
      })
    })
  })

  return flatData
}

// 合并行的方法
function spanMethod({ row, columnIndex, column }) {
  if (column.label === 'From Major City' || column.label === 'No' || column.label === 'Action') {
    // 如果有值需要合并
    if (row.firstRowSpan > 0) {
      return {
        rowspan: row.firstRowSpan,
        colspan: 1,
      }
    } else {
      return {
        rowspan: 0,
        colspan: 0,
      }
    }
  }
  if (column.label === 'Level' || column.label === 'To Major City') {
    // 如果有值需要合并
    if (row.secondRowSpan > 0) {
      return {
        rowspan: row.secondRowSpan,
        colspan: 1,
      }
    } else {
      return {
        rowspan: 0,
        colspan: 0,
      }
    }
  }
}

const tableData = ref(flattenDataWithRowspan(testData))
</script>

<template>
  <div>
    <el-table :data="tableData" :span-method="spanMethod" border>
      <el-table-column label="No" type="index" width="55" align="center"></el-table-column>
      <el-table-column label="From Major City" prop="fromMajorCity" width="200" align="center"></el-table-column>
      <el-table-column label="Level" prop="level" width="100" align="center"></el-table-column>
      <el-table-column label="To Major City" prop="toMajorCity" width="200" align="center"></el-table-column>
      <el-table-column label="Weight (>)" prop="weightGt" width="150" align="center"></el-table-column>
      <el-table-column label="Weight (<=)" prop="weightLte" width="150" align="center"></el-table-column>
      <el-table-column label="Basic Weight (kg)" prop="basic_weight" width="150" align="center"></el-table-column>
      <el-table-column label="Starting Price" prop="starting_price" width="150" align="center"></el-table-column>
      <el-table-column label="Thereafter Price" prop="thereafter_price" width="150" align="center"></el-table-column>
      <el-table-column label="per N Kg" prop="perNkg" width="150" align="center"></el-table-column>
      <el-table-column label="Action" width="200" align="center" fixed="right">
        <template #default>
          <el-button type="primary">Edit</el-button>
          <el-button type="primary">Copy</el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<style scoped></style>
相关推荐
举个栗子dhy几秒前
第一章、React + TypeScript + Webpack项目构建
前端·javascript·react.js
大杯咖啡4 分钟前
localStorage与sessionStorage的区别
前端·javascript
RaidenLiu16 分钟前
告别陷阱:精通Flutter Signals的生命周期、高级API与调试之道
前端·flutter·前端框架
非凡ghost16 分钟前
HWiNFO(专业系统信息检测工具)
前端·javascript·后端
非凡ghost19 分钟前
FireAlpaca(免费数字绘图软件)
前端·javascript·后端
非凡ghost25 分钟前
Sucrose Wallpaper Engine(动态壁纸管理工具)
前端·javascript·后端
拉不动的猪27 分钟前
为什么不建议项目里用延时器作为规定时间内的业务操作
前端·javascript·vue.js
该用户已不存在34 分钟前
Gemini CLI 扩展,把Nano Banana 搬到终端
前端·后端·ai编程
地方地方35 分钟前
前端踩坑记:解决图片与 Div 换行间隙的隐藏元凶
前端·javascript
炒米233338 分钟前
【Array】数组的方法
javascript