vue3 ts [ { "name": "90天包看", "productId": "63ec443f61b1c52b68ff9a4b", "commodityId": "641c340f3a7eb32ffaa6d894", "channel": "微信", "cost": "3.00", "price": "59.00", "remark": "90天的无限流量套餐", "createBy": "admin", "createTime": "2023-03-23 19:12:15", "autoRenewal": false, "enable": true }, { "name": "90天包看", "productId": "63ec443f61b1c52b68ff9a4b", "commodityId": "641c340f3a7eb32ffaa6d89c", "channel": "支付宝", "cost": "3.00", "price": "59.00", "remark": "90天的无限流量套餐", "createBy": "admin", "createTime": "2023-03-23 19:12:15", "autoRenewal": false, "enable": true }, { "name": "90天包看", "productId": "63ec443f61b1c52b68ff9a4b", "commodityId": "64b8ec59db53f2275767efc6", "channel": "支付宝", "cost": "3.00", "price": "49.00", "remark": "90天的无限流量套餐", "createBy": "admin", "createTime": "2023-07-20 16:12:09", "autoRenewal": true, "enable": true }, { "name": "90天包看", "productId": "63ec443f61b1c52b68ff9a4b", "commodityId": "6549ab919702e0536c29bfbe", "channel": "微信", "cost": "3.00", "price": "49.00", "remark": "90天的无限流量套餐", "createBy": "admin", "createTime": "2023-11-07 11:14:25", "autoRenewal": true, "enable": true }, { "name": "180天包看", "productId": "63ec443f61b1c52b68ff9a4f", "commodityId": "641c340f3a7eb32ffaa6d8a4", "channel": "微信", "cost": "5.00", "price": "99.00", "remark": "180天的无限流量套餐", "createBy": "admin", "createTime": "2023-03-23 19:12:15", "autoRenewal": false, "enable": true }, { "name": "180天包看", "productId": "63ec443f61b1c52b68ff9a4f", "commodityId": "641c340f3a7eb32ffaa6d8ac", "channel": "支付宝", "cost": "5.00", "price": "99.00", "remark": "180天的无限流量套餐", "createBy": "admin", "createTime": "2023-03-23 19:12:15", "autoRenewal": false, "enable": true }, { "name": "360天包看", "productId": "63ec443f61b1c52b68ff9a53", "commodityId": "641c340f3a7eb32ffaa6d8b4", "channel": "微信", "cost": "8.00", "price": "169.00", "remark": "360天的无限流量套餐", "createBy": "admin", "createTime": "2023-03-23 19:12:15", "autoRenewal": false, "enable": true }, { "name": "360天包看", "productId": "63ec443f61b1c52b68ff9a53", "commodityId": "641c340f3a7eb32ffaa6d8bc", "channel": "支付宝", "cost": "8.00", "price": "169.00", "remark": "360天的无限流量套餐", "createBy": "admin", "createTime": "2023-03-23 19:12:15", "autoRenewal": false, "enable": true }, { "name": "720天包看", "productId": "6413d36f98057e4c738d2e94", "commodityId": "641c340f3a7eb32ffaa6d8c4", "channel": "微信", "cost": "15.00", "price": "269.00", "remark": "720天的无限流量套餐", "createBy": "admin", "createTime": "2023-03-23 19:12:15", "autoRenewal": false, "enable": true }, { "name": "720天包看", "productId": "6413d36f98057e4c738d2e94", "commodityId": "641c34103a7eb32ffaa6d8cc", "channel": "支付宝", "cost": "15.00", "price": "269.00", "remark": "720天的无限流量套餐", "createBy": "admin", "createTime": "2023-03-23 19:12:16", "autoRenewal": false, "enable": true } ] 数据在<el-table v-loading="listStore.listLoading" border :data="listStore.list" style="width: 100%;" :cell-style="{textAlign:'center'}" :header-cell-style="{textAlign:'center'}" :span-method="objectSpanMethod" > <el-table-column type="index" label="序号" width="60" /> <!-- <el-table-column prop="name" label="套餐类型" show-overflow-tooltip />--> <el-table-column prop="commodityId" label="商品ID" show-overflow-tooltip /> <el-table-column prop="name" label="套餐名称" show-overflow-tooltip /> <el-table-column prop="channel" label="销售渠道" show-overflow-tooltip> <template #default="{ row }"> {{ row.autoRenewal ? row.channel + "(自动续费)" : row.channel }} </template> </el-table-column> <el-table-column prop="price" label="默认售价" show-overflow-tooltip /> <el-table-column prop="cost" label="默认成本" show-overflow-tooltip /> <el-table-column prop="remark" label="套餐说明" show-overflow-tooltip /> <el-table-column prop="createBy" label="创建人" show-overflow-tooltip /> <el-table-column prop="lastUpdate" label="创建时间" show-overflow-tooltip> <template #default="{ row }"> {{ row.insertTime ? moment(row.insertTime).format("YYYY-MM-DD HH:mm:ss") : "--" }} </template> </el-table-column> <el-table-column label="状态"> <template #default="{ row }"> <el-switch v-model="row.enable" :disabled="listStore.disabled" @change="changeSwich(row)" /> </template> </el-table-column> <el-table-column label="操作" width="200"> <template #default="{ row }"> <el-button>编辑套餐{{row.cost}}</el-button> </template> </el-table-column>中,套餐名称和操作合并单元格怎么实现
时间: 2025-05-31 08:49:25 浏览: 15
### 合并单元格的具体实现
在 Vue3 和 TypeScript 的环境下,使用 Element Plus 的 `el-table` 组件可以通过配置 `span-method` 属性来实现单元格的合并功能。以下是基于 `productId` 相同的情况下,合并套餐名称(第三列)和操作列(第十一列)单元格的具体实现方法。
#### 代码实现
以下是一个完整的解决方案:
```typescript
<template>
<el-table
:data="tableData"
border
style="width: 100%"
:span-method="objectSpanMethod"
>
<!-- 假设表格有若干列 -->
<el-table-column prop="name" label="Name" width="180"></el-table-column>
<el-table-column prop="price" label="Price" width="180"></el-table-column>
<el-table-column prop="packageName" label="Package Name" width="180"></el-table-column> <!-- 第三列 -->
<el-table-column prop="operation" label="Operation" width="180"> </el-table-column> <!-- 第十一列 -->
</el-table>
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs } from "vue";
export default defineComponent({
setup() {
const state = reactive({
tableData: [
{ name: "Item1", price: 100, packageName: "Basic", operation: "Edit", productId: 1 },
{ name: "Item2", price: 200, packageName: "Basic", operation: "Edit", productId: 1 },
{ name: "Item3", price: 300, packageName: "Pro", operation: "Delete", productId: 2 },
{ name: "Item4", price: 400, packageName: "Pro", operation: "View", productId: 2 },
],
});
// 计算 span 方法所需的辅助数据
const getSpanArr = () => {
let pos = 0;
const countMap: Record<number, number[]> = {};
state.tableData.forEach((_, index) => {
const key = state.tableData[index].productId;
if (!countMap[key]) {
countMap[key] = [];
}
countMap[key].push(index);
});
return Object.values(countMap).map((arr) => ({
start: arr[0],
length: arr.length,
}));
};
const objectSpanMethod = ({ row, column, rowIndex, columnIndex }: any) => {
const spans = getSpanArr();
const currentPos = spans.find(
(s) => s.start <= rowIndex && rowIndex < s.start + s.length
);
if (
!currentPos ||
!(columnIndex === 2 || columnIndex === 10) // 判断是否为需要合并的列
) {
return { rowspan: 1, colspan: 1 };
}
if (rowIndex % currentPos!.length === 0) {
return { rowspan: currentPos!.length, colspan: 1 }; // 需要合并的情况
} else {
return { rowspan: 0, colspan: 0 }; // 被隐藏的部分
}
};
return { ...toRefs(state), objectSpanMethod };
},
});
</script>
```
---
#### 关键点解析
1. **计算合并范围**
使用 `getSpanArr()` 函数遍历 `tableData` 数据,记录相同 `productId` 对应的起始索引和长度[^1]。这一步是为了动态生成每一组需要合并的数据区间。
2. **定义 `span-method`**
在 `objectSpanMethod` 中判断当前单元格所在的行列位置以及其对应的 `productId` 是否满足合并条件。如果满足,则返回 `{ rowspan: N, colspan: 1 }` 表示该单元格向下跨行;否则返回 `{ rowspan: 0, colspan: 0 }` 将多余部分隐藏。
3. **指定需合并的列**
只针对特定列(这里是第三列和第十一列)应用合并逻辑,在其他列保持默认显示方式[^1]。
---
#### 注意事项
- 确保 `row-key` 已正确定义以便支持复杂场景下的选中状态管理。
- 如果数据量较大或者频繁更新,建议优化性能,比如缓存 `spans` 结果以减少重复计算开销。
---
###
阅读全文
相关推荐


















