vue3 elementplus el-table :span-method 动态合并数据相同的指定列单元格

642 阅读1分钟

1.业务需求:

合并指定的列 相同数据的单元格

2.效果展示:

企业微信截图_16941543694042.png

3. 实现思路:

el-table组件主要靠span-method方法实现合并

表格数据是后端提供的动态数据

实现代码

  <template> 
    <el-card class="full-table" shadow="hover" style="margin-top: 8px">
        <el-table :data="state.tableData" :span-method="objectSpanMethod">
            <el-table-column " prop="aaa" label="aaa" show-overflow-tooltip />
            <el-table-column  prop="bbb" label="bbb" show-overflow-tooltip />
            <el-table-column  prop="ccc" label="ccc" show-overflow-tooltip />
            <el-table-column  prop="ddd" label="ddd" show-overflow-tooltip />
            <el-table-column  prop="eee" label="eee" show-overflow-tooltip />
        </el-table>
    </el-card> 
  </template>

<script lang="ts" setup name="aaa">
import { onMounted, reactive } from 'vue';
import type { TableColumnCtx } from 'element-plus'
import { getAPI } from '/@/utils/axios-utils';
import { api } from '/@/api-services/api';
import { detailInput, } from '/@/api-services/models';

interface SpanMethodProps {
    row: detailInput
    column: TableColumnCtx<detailInput>
    rowIndex: number
    columnIndex: number
}
const state = reactive({
    loading: false,
    tableData: [] as any,
    queryParams: {
        warehouseId: 0,
        inventoryId: 0,
        isCloud: 0,
        includeZero: 0
    }, 
    cellList1: [] as any, // 第一列合并单元格信息
    cellList2: [] as any, // 其他列合并单元格信息
});

onMounted(async () => {
    await handleQuery();  
});

// 获取列表数据
const handleQuery = async () => {
    state.loading = true
    let params = Object.assign(state.queryParams);
    let res = await getAPI(api).apiPost(params);
    state.tableData = res.data.result ?? []
    state.loading = false
    //将相同的仓库Id排序,方便后续合并
    let idList = state.tableData.sort((a: any, b: any) => {
        return a.warehouseId - b.warehouseId
    })
    state.cellList1 = computeCell(idList, "warehouseId", 'inventoryId');
    state.cellList2 = computeCell(idList, "inventoryId", "warehouseId");
}   
//  根据需要合并的单元格字段排序
const computeCell = (tableBody: any, key: any, key1: any) => {
     // tableBody 为 表格数据 , key,key1 为需要合并的字段
    let cellList = [];
    let count: any;
    for (let i = 0; i < tableBody.length; i++) {
        if (i == 0) {
            cellList.push(1);
            count = 0;
        } else {
            //  其他列需要满足的条件
            if (key == 'inventoryId') {
                if (tableBody[i][key] == tableBody[i - 1][key] && tableBody[i][key1] == tableBody[i - 1][key1]) {
                    // 比较前后两个元素是否相等,相等的话对应索引的元素的值+1,并且在其后增加一个0占位(防止合并过后表格数据错位),否则的话增加一个1占位,并记录当前索引,往复循环,构造一个给 rowspan 取值判断合并的数组: 
                    cellList[count] += 1;
                    cellList.push(0);
                } else {
                    cellList.push(1);
                    count = i;
                }
            } else {
                //  第一列需要满足的条件
                if (tableBody[i][key] == tableBody[i - 1][key]) {
                    cellList[count] += 1;
                    cellList.push(0);
                } else {
                    cellList.push(1);
                    count = i;
                }
            }
        }
    }
    return cellList;
}
// 合并单元格
const mergeCellVertical = (cellList: any, rowIndex: any) => {
    const rowCell = cellList[rowIndex];
    if (rowCell > 0) {
        const colCell = 1;
        return {
            rowspan: rowCell,
            colspan: colCell,
        };
    } else {
        return {
            rowspan: 0,
            colspan: 0,
        };
    }
}
// 合并单元格
const objectSpanMethod = ({ row, column, rowIndex, columnIndex }: SpanMethodProps) => {
    // 第一列的合并 
    if (columnIndex === 0) {
        return mergeCellVertical(state.cellList1, rowIndex);
    }
    // 其他列合并
    if (columnIndex === 1 || columnIndex === 2 || columnIndex === 3) {
        return mergeCellVertical(state.cellList2, rowIndex);
    }
}
</script>