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>
相关推荐
蓝天白云下遛狗12 分钟前
goole chrome变更默认搜索引擎为百度
前端·chrome
come1123435 分钟前
Vue 响应式数据传递:ref、reactive 与 Provide/Inject 完全指南
前端·javascript·vue.js
前端风云志1 小时前
TypeScript结构化类型初探
javascript
musk12121 小时前
electron 打包太大 试试 tauri , tauri 安装打包demo
前端·electron·tauri
翻滚吧键盘2 小时前
js代码09
开发语言·javascript·ecmascript
万少2 小时前
第五款 HarmonyOS 上架作品 奇趣故事匣 来了
前端·harmonyos·客户端
OpenGL2 小时前
Android targetSdkVersion升级至35(Android15)相关问题
前端
rzl023 小时前
java web5(黑马)
java·开发语言·前端
Amy.Wang3 小时前
前端如何实现电子签名
前端·javascript·html5
海天胜景3 小时前
vue3 el-table 行筛选 设置为单选
javascript·vue.js·elementui