elementPlus实现动态表格单元格合并span-method方法总结

最近在做PC端需求的时候,需要把首列中相邻的同名称单元格合并。

我看了一下elementPlus官网中的table表格,span-method可以实现单元格合并。

我们先看一下官网的例子:

合并行或列

多行或多列共用一个数据时,可以合并行或列。

通过给 table 传入span-method方法可以实现合并行或列, 方法的参数是一个对象,里面包含当前行 row、当前列 column、当前行号 rowIndex、当前列号 columnIndex 四个属性。 该函数可以返回一个包含两个元素的数组,第一个元素代表 rowspan,第二个元素代表 colspan。 也可以返回一个键名为 rowspan 和 colspan 的对象。
rowspan:合并几行
colspan:合并几列

html 复制代码
<template>
  <div>
    <el-table
      :data="tableData"
      :span-method="arraySpanMethod"
      border
      style="width: 100%"
    >
      <el-table-column prop="id" label="ID" width="180" />
      <el-table-column prop="name" label="Name" />
      <el-table-column prop="amount1" sortable label="Amount 1" />
      <el-table-column prop="amount2" sortable label="Amount 2" />
      <el-table-column prop="amount3" sortable label="Amount 3" />
    </el-table>

    <el-table
      :data="tableData"
      :span-method="objectSpanMethod"
      border
      style="width: 100%; margin-top: 20px"
    >
      <el-table-column prop="id" label="ID" width="180" />
      <el-table-column prop="name" label="Name" />
      <el-table-column prop="amount1" label="Amount 1" />
      <el-table-column prop="amount2" label="Amount 2" />
      <el-table-column prop="amount3" label="Amount 3" />
    </el-table>
  </div>
</template>

<script lang="ts" setup>
import type { TableColumnCtx } from 'element-plus'

interface User {
  id: string
  name: string
  amount1: string
  amount2: string
  amount3: number
}

interface SpanMethodProps {
  row: User
  column: TableColumnCtx<User>
  rowIndex: number
  columnIndex: number
}

const arraySpanMethod = ({
  row,
  column,
  rowIndex,
  columnIndex,
}: SpanMethodProps) => {
  if (rowIndex % 2 === 0) {
    if (columnIndex === 0) {
      return [1, 2] // // 合并1行 合并2列
    } else if (columnIndex === 1) {
      return [0, 0]
    }
  }
}

const objectSpanMethod = ({
  row,
  column,
  rowIndex,
  columnIndex,
}: SpanMethodProps) => {
  if (columnIndex === 0) {
    if (rowIndex % 2 === 0) {  // 2、4、6、8......
      return {
        rowspan: 2, // 合并2行
        colspan: 1, // 合并1列
      }
    } else {
      return {
        rowspan: 0,
        colspan: 0,
      }
    }
  }
}

const tableData: User[] = [
  {
    id: '12987122',
    name: 'Tom',
    amount1: '234',
    amount2: '3.2',
    amount3: 10,
  },
  {
    id: '12987123',
    name: 'Tom',
    amount1: '165',
    amount2: '4.43',
    amount3: 12,
  },
  {
    id: '12987124',
    name: 'Tom',
    amount1: '324',
    amount2: '1.9',
    amount3: 9,
  },
  {
    id: '12987125',
    name: 'Tom',
    amount1: '621',
    amount2: '2.2',
    amount3: 17,
  },
  {
    id: '12987126',
    name: 'Tom',
    amount1: '539',
    amount2: '4.1',
    amount3: 15,
  },
]
</script>

效果如下:

好了,官网例子看过,来看看我在实际项目中是怎么应用的。

需要处理的数据如下:

javascript 复制代码
let data = [
            {
                firstName: '基本证照',
                code: '001',
                secondName: '营业执照',
                sort: '30',
                fileList: [
                    {
                        id: '1',
                        name: '营业执照照片'
                    }
                ]
            },
            {
                firstName: '基本证照',
                code: '002',
                secondName: '身份证照',
                sort: '40',
                fileList: [
                    {
                        id: '2',
                        name: '身份证照照片'
                    }
                ]
            },
            {
                firstName: '现场照片',
                code: '003',
                secondName: '公司前台照',
                sort: '50',
                fileList: [
                    {
                        id: '3',
                        name: '公司前台照照片'
                    }
                ]
            },
            {
                firstName: '现场照片',
                code: '004',
                secondName: '公司工位照',
                sort: '60',
                fileList: [
                    {
                        id: '4',
                        name: '公司工位照照片'
                    }
                ]
            },
            {
                firstName: '经营证明',
                code: '005',
                secondName: '工厂生产照',
                sort: '70',
                fileList: [
                    {
                        id: '5',
                        name: '工厂生产照照片'
                    }
                ]
            }
        ]

需要展示的效果是:

首列中只有三行(基本证照、现场照片、经营证明)

也就是说 基本证照、现场照片这个两个首列需要合并两行

封装的函数如下,函数中都是注释,对函数中的定义和字段做了详细的说明。

javascript 复制代码
        // 合并单元格规则(data为表格数据,cateName为合并字段的名称)这个函数的作用是对首列中的行进行合并
        function objSpanMethod({ row, column, rowIndex, columnIndex }, data, cateName) {
            // 非首列的数据都返回,不往下进行
            if (columnIndex !== 0) {
                return
            }
            let arrLength = [] // 存放secondName对应的数据数组长度
            let cateRows = [] // 存放起始合并行以及合并行数
            data.reduce((preValue, curValue, index, array) => {
                if (index == 0 || preValue[cateName] != curValue[cateName]) {
                    arrLength.push(1)
                } else {
                    arrLength[arrLength - 1]++
                }
                return curValue
            }, data[0])

            // 获取存放起始合并行以及合并行数
            arrLength.reduce((pre, cur, index, value) => { // pre指的是上一次计算过后的prev + cur这个值
                cateRows.push({ rowIndex: prev, rowspan: cur }); // rowIndex指的是从第几行开始合并,rowspan指的是合并几行
                return prev + cur
            }, 0)

            let intRowSpan = 0;
            for (let i = 0; i < arrLength.length; i++) {
                if (cateRows[i].rowIndex == rowIndex) {
                    intRowSpan = cateRows[i].rowspan;
                    break;
                }
            }
            return {
                // 当渲染执行到某一行的首列时,或者执行到首列时,对其中的行进行渲染时,例如渲染到第四行时,发现rowspan为3时,
                // 那就是首列中从第四行开始合并,合并3行,四、五、六这三行合并为一行。
                rowspan: intRowSpan,
                colspan: intRowSpan == 0 ? 0 : 1  // 如果不合并行,就返回0,说白了就不合并
            }
        }

具体的使用请看以下完整的代码:

html 复制代码
<template>
  <div class="table">
    <el-table
      :data="data"
      :span-method="(param) => objSpanMethod(param, data, 'firstName')"
    >
      <el-table-colum prop="firstName" label="资料分类" width="150" />
      <el-table-colum prop="secondName" label="资料名称" />
      <el-table-colum prop="fileList" label="已上传资料">
        <template #default="{ row }">
          <p v-for="(item,index)" in row.fileList :key="item?.name + index">
            <span>
              {{ item?.name }}
            </span>
          </p>
        </template>
      </el-table-colum>
    </el-table>
  </div>
</template>

<script setup>
// data是接口请求回来的数据
// 数据如下:
let data = [
  {
    firstName: "基本证照",
    code: "001",
    secondName: "营业执照",
    sort: "30",
    fileList: [
      {
        id: "1",
        name: "营业执照照片",
      },
    ],
  },
  {
    firstName: "基本证照",
    code: "002",
    secondName: "身份证照",
    sort: "40",
    fileList: [
      {
        id: "2",
        name: "身份证照照片",
      },
    ],
  },
  {
    firstName: "现场照片",
    code: "003",
    secondName: "公司前台照",
    sort: "50",
    fileList: [
      {
        id: "3",
        name: "公司前台照照片",
      },
    ],
  },
  {
    firstName: "现场照片",
    code: "004",
    secondName: "公司工位照",
    sort: "60",
    fileList: [
      {
        id: "4",
        name: "公司工位照照片",
      },
    ],
  },
  {
    firstName: "经营证明",
    code: "005",
    secondName: "工厂生产照",
    sort: "70",
    fileList: [
      {
        id: "5",
        name: "工厂生产照照片",
      },
    ],
  },
];

// 合并单元格规则(data为表格数据,cateName为合并字段的名称)这个函数的作用是对首列中的行进行合并
function objSpanMethod({ row, column, rowIndex, columnIndex }, data, cateName) {
  // 非首列的数据都返回,不往下进行
  if (columnIndex !== 0) {
    return;
  }
  let arrLength = []; // 存放secondName对应的数据数组长度
  let cateRows = []; // 存放起始合并行以及合并行数
  data.reduce((preValue, curValue, index, array) => {
    if (index == 0 || preValue[cateName] != curValue[cateName]) {
      arrLength.push(1);
    } else {
      arrLength[arrLength - 1]++;
    }
    return curValue;
  }, data[0]);

  // 获取存放起始合并行以及合并行数
  arrLength.reduce((pre, cur, index, value) => {
    // pre指的是上一次计算过后的prev + cur这个值
    cateRows.push({ rowIndex: prev, rowspan: cur }); // rowIndex指的是从第几行开始合并,rowspan指的是合并几行
    return prev + cur;
  }, 0);

  let intRowSpan = 0;
  for (let i = 0; i < arrLength.length; i++) {
    if (cateRows[i].rowIndex == rowIndex) {
      intRowSpan = cateRows[i].rowspan;
      break;
    }
  }
  return {
    // 当渲染执行到某一行的首列时,或者执行到首列时,对其中的行进行渲染时,例如渲染到第四行时,发现rowspan为3时,
    // 那就是首列中从第四行开始合并,合并3行,四、五、六这三行合并为一行。
    rowspan: intRowSpan,
    colspan: intRowSpan == 0 ? 0 : 1, // 如果不合并行,就返回0,说白了就不合并
  };
}
</script>

<style>
</style>

这样就完全实现了首列中行的合并。总结这些呢,主要是记录下rowspan:合并几行
colspan:合并几列
这个规则,还是就是合并行中对于数据的处理。

好记性不如烂笔头,虽然当时明白的很好,但是还是总结记录下来最好。

相关推荐
十一吖i14 天前
前端将后端返回的文件下载到本地
vue.js·elementplus
bjzhang753 个月前
单HTML文件集成vue3+ElementPlus的使用
vue3·elementplus
AvatarGiser4 个月前
《ElementUI/Plus 基础知识》el-tree 之修改可拖拽节点的高亮背景和线
前端·javascript·elementui·elementplus
低保和光头哪个先来5 个月前
Vue3中使用el-table遇到的问题
vue.js·typescript·elementplus
红烧咸咸鱼6 个月前
element table表格行列合并span-method,根据数据动态行列合并
element·span-method·element表格行列合并·表格动态行列合并
杜sir20106 个月前
Vue3+ElementPlus+TS开发业务功能的问题汇总(持续更新)
前端·vue3·elementplus
Li_Ning216 个月前
element-plus el-time-picker 时间段选择(可多选)
前端·vue3·elementplus
AvatarGiser7 个月前
《ElementUI 基础知识》el-tabs header 监听鼠标中键滚动时左右滑动(ElementPlus同样适用)
elementui·elementplus·tabs
Li_Ning217 个月前
Vue3 el-dialog 二次封装踩坑实录(v-model moduleValue 不触发)
前端·elementplus·el-dialog二次封装
以明志、7 个月前
ASP.NET前后端分离,WebApi。Vue3+ElementPlus+Axios+Pinia全流程教程
后端·asp.net·vue3·elementplus·前后端分离