Element Plus table 列合并 实现效果

         vue3+ts,tag样式使用的是colorUi 的tag 和 bg 样式 ,然后改了单位,合并通过table 的 span-method 实现

1、实现效果

        

2、代码

<template>
	<div class="app-container">
		<el-card shadow="never" class="table-container">
			<el-table ref="dataTableRef" class="table-card-container" :border="false" :span-method="spanMethod" :data="state.data" size="large">
				<el-table-column align="center" label="学员" prop="student" fixed />
				<el-table-column align="center" label="身份" prop="role" fixed />
				<el-table-column align="center" label="培养月数" prop="studyMonth" width="100" fixed />
				<el-table-column align="center" label="轮转月数" prop="roteMonth" width="100" fixed />
				<el-table-column align="center">
					<template #header>
						<div class="table-head">
							<div class="header-item">
								<div class="centered-content">
									{{ `${state.command}年` }}
									<el-dropdown @command="handleCommand">
										<i-ep-arrow-down class="action-more" />
										<template #dropdown>
											<el-dropdown-menu>
												<el-dropdown-item v-for="year in state.years" :key="year" :command="year"> {{ year }}年 </el-dropdown-item>
											</el-dropdown-menu>
										</template>
									</el-dropdown>
								</div>
							</div>
						</div>
					</template>
					<template v-for="(month, index) in 12" :key="index">
						<el-table-column :label="`${month}月`" :prop="`departments[${month - 1}]`" align="center">
							<template #default="{ row: { departments } }">
								<span round class="cu-tag light round" :class="colors[departments[month - 1]]" style="width: 100%">
									{{ departments[month - 1] }}
								</span>
							</template>
						</el-table-column>
					</template>
				</el-table-column>
			</el-table>
		</el-card>
	</div>
</template>

<script setup lang="ts">
interface RoteObj {
	student: string;
	role: string;
	studyMonth: string;
	roteMonth: string;
	year: string;
	departments: [];
}
const state = reactive({
	command: 2023,
	years: [2023, 2024, 2025],
	data: [
		{
			student: '张三',
			role: '专硕',
			studyMonth: '1',
			roteMonth: '1',
			year: '2023',
			departments: ['骨科', '麻醉科', '超声科', '超声科', '儿科', '重症医学科', '重症医学科', '消化内科', '消化内科', '急诊科', '急诊科', '急诊科'],
		},
		{
			student: '李四',
			role: '专硕',
			studyMonth: '1',
			roteMonth: '1',
			year: '2023',
			departments: ['骨科', '麻醉科', '麻醉科', '骨科', '骨科', '急诊科', '儿科', '消化内科', '重症医学科', '重症医学科', '急诊科', '急诊科'],
		},
		{
			student: '王五',
			role: '专硕',
			studyMonth: '1',
			roteMonth: '1',
			year: '2023',
			departments: ['重症医学科', '重症医学科', '儿科', '儿科', '骨科', '骨科', '重症医学科', '消化内科', '消化内科', '急诊科', '超声科', '超声科'],
		},
		{
			student: '赵六',
			role: '专硕',
			studyMonth: '1',
			roteMonth: '1',
			year: '2023',
			departments: ['骨科', '骨科', '骨科', '超声科', '重症医学科', '重症医学科', '重症医学科', '消化内科', '消化内科', '急诊科', '急诊科', '急诊科'],
		},
	],
});
const colors = {
	骨科: 'bg-red',
	麻醉科: 'bg-orange',
	超声科: 'bg-yellow',
	重症医学科: 'bg-olive',
	消化内科: 'bg-green',
	急诊科: 'bg-cyan',
	儿科: 'bg-blue',
};
const spanMethod = ({ row, column, rowIndex, columnIndex }: { row: RoteObj; column: any; rowIndex: number; columnIndex: number }) => {
	// console.log(row, column, rowIndex, columnIndex);
	// 科室表格开始列下标
	if (columnIndex > 3) {
		const k = columnIndex - 4;
		const { departments } = row;
		const department = departments[k];
		if (k > 0 && department == departments[k - 1]) return [0, 0];
		else if (k < 11) {
			const span = [0, 0];
			for (let i = k; i < departments.length; i++) {
				if (departments[i] == department) {
					span[1] += 1;
				} else break;
			}
			if (span[1] > 0) {
				span[0] = 1;
				return span;
			}
		}
	}
};

/**
 * 选择菜单
 * @param command
 */
const handleCommand = (command: number) => {
	state.command = command;
};
</script>

<style lang="scss" scoped>
.table-container {
	:deep(.cell) {
		padding: 0 !important;
	}
	:deep(td) {
		border-right: 0 !important;
		padding-right: 1px;
	}
}

/* ==================
          徽章
 ==================== */

.cu-tag {
	font-size: 14px;
	vertical-align: middle;
	position: relative;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	padding: 0px 8px;
	height: 24px;
	font-family:
		Helvetica Neue,
		Helvetica,
		sans-serif;
	white-space: nowrap;
}

.cu-tag:not([class*='bg']):not([class*='line']) {
	background-color: #f1f1f1;
}

.cu-tag[class*='line-']::after {
	content: ' ';
	width: 200%;
	height: 200%;
	position: absolute;
	top: 0;
	left: 0;
	border: 1px solid currentColor;
	transform: scale(0.5);
	transform-origin: 0 0;
	box-sizing: border-box;
	border-radius: inherit;
	z-index: 1;
	pointer-events: none;
}

.cu-tag.radius[class*='line']::after {
	border-radius: 6px;
}

.cu-tag.round {
	border-radius: 500px;
}

.cu-tag[class*='line-']::after {
	border-radius: 0;
}

.cu-tag + .cu-tag {
	margin-left: 5px;
}

.cu-tag.sm {
	font-size: 10px;
	padding: 0px 6px;
	height: 16px;
}

.cu-capsule {
	display: inline-flex;
	vertical-align: middle;
}

.cu-capsule + .cu-capsule {
	margin-left: 5px;
}

.cu-capsule .cu-tag {
	margin: 0;
}

.cu-capsule .cu-tag[class*='line-']:last-child::after {
	border-left: 0px solid transparent;
}

.cu-capsule .cu-tag[class*='line-']:first-child::after {
	border-right: 0px solid transparent;
}

.cu-capsule.radius .cu-tag:first-child {
	border-top-left-radius: 3px;
	border-bottom-left-radius: 3px;
}

.cu-capsule.radius .cu-tag:last-child::after,
.cu-capsule.radius .cu-tag[class*='line-'] {
	border-top-right-radius: 6px;
	border-bottom-right-radius: 6px;
}

.cu-capsule.round .cu-tag:first-child {
	border-top-left-radius: 100px;
	border-bottom-left-radius: 100px;
	text-indent: 2px;
}

.cu-capsule.round .cu-tag:last-child::after,
.cu-capsule.round .cu-tag:last-child {
	border-top-right-radius: 100px;
	border-bottom-right-radius: 100px;
	text-indent: -2px;
}

.cu-tag.badge {
	border-radius: 100px;
	position: absolute;
	top: -5px;
	right: -5px;
	font-size: 10px;
	padding: 0px 5px;
	height: 14px;
	color: #ffffff;
}

.cu-tag.badge:not([class*='bg-']) {
	background-color: #dd514c;
}

.cu-tag:empty:not([class*='cuIcon-']) {
	padding: 0px;
	width: 8px;
	height: 8px;
	top: -2px;
	right: -2px;
}

.cu-tag[class*='cuIcon-'] {
	width: 16px;
	height: 16px;
	top: -2px;
	right: -2px;
}
/* ==================
          背景
 ==================== */

.line-red::after,
.lines-red::after {
	border-color: #e54d42;
}

.line-orange::after,
.lines-orange::after {
	border-color: #f37b1d;
}

.line-yellow::after,
.lines-yellow::after {
	border-color: #fbbd08;
}

.line-olive::after,
.lines-olive::after {
	border-color: #8dc63f;
}

.line-green::after,
.lines-green::after {
	border-color: #39b54a;
}

.line-cyan::after,
.lines-cyan::after {
	border-color: #1cbbb4;
}

.line-blue::after,
.lines-blue::after {
	border-color: #0081ff;
}

.line-purple::after,
.lines-purple::after {
	border-color: #6739b6;
}

.line-mauve::after,
.lines-mauve::after {
	border-color: #9c26b0;
}

.line-pink::after,
.lines-pink::after {
	border-color: #e03997;
}

.line-brown::after,
.lines-brown::after {
	border-color: #a5673f;
}

.line-grey::after,
.lines-grey::after {
	border-color: #8799a3;
}

.line-gray::after,
.lines-gray::after {
	border-color: #aaaaaa;
}

.line-black::after,
.lines-black::after {
	border-color: #333333;
}

.line-white::after,
.lines-white::after {
	border-color: #ffffff;
}

.bg-red {
	background-color: #e54d42;
	color: #ffffff;
}

.bg-orange {
	background-color: #f37b1d;
	color: #ffffff;
}

.bg-yellow {
	background-color: #fbbd08;
	color: #333333;
}

.bg-olive {
	background-color: #8dc63f;
	color: #ffffff;
}

.bg-green {
	background-color: #39b54a;
	color: #ffffff;
}

.bg-cyan {
	background-color: #1cbbb4;
	color: #ffffff;
}

.bg-blue {
	background-color: #0081ff;
	color: #ffffff;
}

.bg-purple {
	background-color: #6739b6;
	color: #ffffff;
}

.bg-mauve {
	background-color: #9c26b0;
	color: #ffffff;
}

.bg-pink {
	background-color: #e03997;
	color: #ffffff;
}

.bg-brown {
	background-color: #a5673f;
	color: #ffffff;
}

.bg-grey {
	background-color: #8799a3;
	color: #ffffff;
}

.bg-gray {
	background-color: #f0f0f0;
	color: #333333;
}

.bg-black {
	background-color: #333333;
	color: #ffffff;
}

.bg-white {
	background-color: #ffffff;
	color: #666666;
}

.bg-shadeTop {
	background-image: linear-gradient(rgba(0, 0, 0, 1), rgba(0, 0, 0, 0.01));
	color: #ffffff;
}

.bg-shadeBottom {
	background-image: linear-gradient(rgba(0, 0, 0, 0.01), rgba(0, 0, 0, 1));
	color: #ffffff;
}

.bg-red.light {
	color: #e54d42;
	background-color: #fadbd9;
}

.bg-orange.light {
	color: #f37b1d;
	background-color: #fde6d2;
}

.bg-yellow.light {
	color: #fbbd08;
	background-color: #fef2ced2;
}

.bg-olive.light {
	color: #8dc63f;
	background-color: #e8f4d9;
}

.bg-green.light {
	color: #39b54a;
	background-color: #d7f0dbff;
}

.bg-cyan.light {
	color: #1cbbb4;
	background-color: #d2f1f0;
}

.bg-blue.light {
	color: #0081ff;
	background-color: #cce6ff;
}

.bg-purple.light {
	color: #6739b6;
	background-color: #e1d7f0;
}

.bg-mauve.light {
	color: #9c26b0;
	background-color: #ebd4ef;
}

.bg-pink.light {
	color: #e03997;
	background-color: #f9d7ea;
}

.bg-brown.light {
	color: #a5673f;
	background-color: #ede1d9;
}

.bg-grey.light {
	color: #8799a3;
	background-color: #e7ebed;
}

.bg-gradual-red {
	background-image: linear-gradient(45deg, #f43f3b, #ec008c);
	color: #ffffff;
}

.bg-gradual-orange {
	background-image: linear-gradient(45deg, #ff9700, #ed1c24);
	color: #ffffff;
}

.bg-gradual-green {
	background-image: linear-gradient(45deg, #39b54a, #8dc63f);
	color: #ffffff;
}

.bg-gradual-purple {
	background-image: linear-gradient(45deg, #9000ff, #5e00ff);
	color: #ffffff;
}

.bg-gradual-pink {
	background-image: linear-gradient(45deg, #ec008c, #6739b6);
	color: #ffffff;
}

.bg-gradual-blue {
	background-image: linear-gradient(45deg, #0081ff, #1cbbb4);
	color: #ffffff;
}
</style>
  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
实现动态合并,可以使用 Element Plus 表格组件提供的 `span-method` 属性。该属性可以设置一个方法,用于动态计算每个单元格需要合并的行数和数。 下面是一个示例代码,使用 TypeScript 和 Element Plus 表格组件实现动态合并: ```typescript <template> <el-table :data="tableData" :span-method="mergeCell" > <el-table-column prop="name" label="名称" /> <el-table-column prop="age" label="年龄" /> <el-table-column prop="gender" label="性别" /> <el-table-column prop="score" label="分数" /> </el-table> </template> <script lang="ts"> import { defineComponent } from 'vue'; import { ElTableColumn, ElTableRow } from 'element-plus'; export default defineComponent({ data() { return { tableData: [ { name: '张三', age: 18, gender: '男', score: 90, }, { name: '李四', age: 20, gender: '女', score: 85, }, { name: '王五', age: 22, gender: '男', score: 95, }, ], }; }, methods: { mergeCell({ row, column, rowIndex, columnIndex }: { row: Record<string, any>; column: ElTableColumn; rowIndex: number; columnIndex: number; }): { rowspan: number; colspan: number; } { // 判断第一是否相同 if (columnIndex === 0) { let rowspan = 1; for (let i = rowIndex + 1; i < this.tableData.length; i++) { if (this.tableData[i].name === row.name) { rowspan++; } else { break; } } return { rowspan, colspan: 1, }; } // 其他不需要合并 return { rowspan: 0, colspan: 0, }; }, }, }); </script> ``` 在上面的代码中,`mergeCell` 方法会接收一个参数,包含当前单元格的行数据、数据、行索引和索引。通过判断第一的值是否相同,动态计算需要合并的行数和数,然后返回一个对象。 需要注意的是,`span-method` 属性的值是一个函数,需要使用 `defineComponent` 方法定义组件,并将该函数作为组件的一个方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

少十步

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值