原来的代码:
// 资金信息表格行点击
const onRowClick = async (row: CapitalInfo) => {
// 防止重复点击
if (row.id === capitalInfoStore.currentSelectedCapitalInfo?.id) {
return;
}
capitalInfoStore.setCurrentSelectedCapitalInfo(row);
};
<!– 资金信息列表 –>
<el-table
ref="capitalInfoTableRef"
:data="capitalInfoStore.capitalInfoList"
v-loading="capitalInfoStore.capitalInfoLoading"
highlight-current-row
stripe
:border="isBorder"
style="height: 100%"
@header-dragend="setTableColumnWidth?.saveColumnWidth"
@row-click="onRowClick">
<!– 数据列 –>
<el-table-column prop="createTime" label="创建时间" width="165" fixed="left" />
<el-table-column prop="capitalNo" label="资金序号" width="150" fixed="left" />
<el-table-column prop="capitalName" label="资金名称" min-width="250" fixed="left" />
<el-table-column prop="capitalType" label="资金类别" min-width="250" />
<el-table-column prop="capitalTotal" label="指标预算总额" width="120" />
<el-table-column prop="capitalLeaveTotal" label="指标剩余额" width="120" />
<el-table-column prop="capitalValidTotal" label="指标可用总额" width="120" />
<el-table-column prop="capitalIndexType" label="指标类别" width="100" />
<el-table-column prop="capitalAccount" label="资金账户" width="100" />
<el-table-column prop="capitalSource" label="资金来源" width="120" />
<el-table-column prop="capitalIndexSource" label="指标来源" width="100" />
<el-table-column prop="capitalYear" label="资金年份" width="100" />
<el-table-column prop="capitalState" label="状态" width="100">
<template #default="scoped">
{{ formatState(scoped.row.capitalState) }}
</template>
</el-table-column>
<el-table-column prop="remark" label="备注信息" width="120" />
<el-table-column label="操作" width="150" header-align="center" align="center" fixed="right">
<template #default="scope">
<BasePreventReClickButton
class="table-btn"
type="primary"
size="default"
link
:loading="false"
@click="onModifyClick(scope.$index, scope.row)"
>{{ scope.row.capitalState === CapitalInfoState.CLOSED ? "查看" : "查改" }}</BasePreventReClickButton
>
<BasePreventReClickButton
class="table-btn"
type="primary"
size="default"
link
:loading="false"
:disabled="scope.row.capitalState === CapitalInfoState.CLOSED"
@click="onCompleteClick(scope.row.id)"
>结案</BasePreventReClickButton
>
<BasePreventReClickButton
class="table-btn"
type="danger"
size="default"
link
:loading="false"
:disabled="scope.row.capitalState === CapitalInfoState.CLOSED"
@click="onDeleteClick(scope.row.id)"
>删除</BasePreventReClickButton
>
</template>
</el-table-column>
</el-table>
增加展开行及逻辑后的代码:
// 资金信息表格行点击
const onRowClick = async (row: CapitalInfo) => {
// 防止重复点击
if (row.id === capitalInfoStore.currentSelectedCapitalInfo?.id) {
return;
}
capitalInfoStore.setCurrentSelectedCapitalInfo(row);
};
// 资金信息表格行展开
const onExpandChange = async (row: CapitalInfo, expandedRows: CapitalInfo[]) => {
// 如果是展开操作,检查当前点击的行是否已经在展开的行数组中
if (expandedRows.some((expandedRow) => expandedRow.id === row.id)) {
// 获取资金分配明细列表
await capitalInfoStore.getCapitalAllocateDetailList(row);
}
};
// 获取展开行的key
const getRowKey = (row: CapitalInfo) => {
return String(row.id);
};
<!– 资金信息列表 –>
<el-table
ref="capitalInfoTableRef"
:data="capitalInfoStore.capitalInfoList"
v-loading="capitalInfoStore.capitalInfoLoading"
highlight-current-row
stripe
:border="isBorder"
style="height: 100%"
@header-dragend="setTableColumnWidth?.saveColumnWidth"
@row-click="onRowClick"
@expand-change="onExpandChange"
:row-key="getRowKey">
<!– 展开列 –>
<el-table-column type="expand" width="48" fixed="left">
<template #default="scope">
<div>
<el-table :data="scope.row.capitalAllocateDetailList">
<el-table-column prop="index" label="" width="48" show-overflow-tooltip />
<el-table-column prop="deptName" label="指标使用部门" width="315" show-overflow-tooltip />
<el-table-column prop="total" label="指标分配金额" width="125" show-overflow-tooltip />
<el-table-column prop="budget" label="预算情况" width="125" show-overflow-tooltip />
<el-table-column prop="payType" label="支出分类" width="125" show-overflow-tooltip />
<el-table-column prop="payMode" label="支出方式" width="125" show-overflow-tooltip />
<el-table-column prop="validTotal" label="当前可使用额" width="120" show-overflow-tooltip />
<el-table-column prop="assistDeptName" label="协助部门" min-width="250" show-overflow-tooltip />
</el-table>
</div>
</template>
</el-table-column>
<!– 数据列 –>
<el-table-column prop="createTime" label="创建时间" width="165" fixed="left" />
<el-table-column prop="capitalNo" label="资金序号" width="150" fixed="left" />
<el-table-column prop="capitalName" label="资金名称" min-width="250" fixed="left" />
<el-table-column prop="capitalType" label="资金类别" min-width="250" />
<el-table-column prop="capitalTotal" label="指标预算总额" width="120" />
<el-table-column prop="capitalLeaveTotal" label="指标剩余额" width="120" />
<el-table-column prop="capitalValidTotal" label="指标可用总额" width="120" />
<el-table-column prop="capitalIndexType" label="指标类别" width="100" />
<el-table-column prop="capitalAccount" label="资金账户" width="100" />
<el-table-column prop="capitalSource" label="资金来源" width="120" />
<el-table-column prop="capitalIndexSource" label="指标来源" width="100" />
<el-table-column prop="capitalYear" label="资金年份" width="100" />
<el-table-column prop="capitalState" label="状态" width="100">
<template #default="scoped">
{{ formatState(scoped.row.capitalState) }}
</template>
</el-table-column>
<el-table-column prop="remark" label="备注信息" width="120" />
<el-table-column label="操作" width="150" header-align="center" align="center" fixed="right">
<template #default="scope">
<BasePreventReClickButton
class="table-btn"
type="primary"
size="default"
link
:loading="false"
@click="onModifyClick(scope.$index, scope.row)"
>{{ scope.row.capitalState === CapitalInfoState.CLOSED ? "查看" : "查改" }}</BasePreventReClickButton
>
<BasePreventReClickButton
class="table-btn"
type="primary"
size="default"
link
:loading="false"
:disabled="scope.row.capitalState === CapitalInfoState.CLOSED"
@click="onCompleteClick(scope.row.id)"
>结案</BasePreventReClickButton
>
<BasePreventReClickButton
class="table-btn"
type="danger"
size="default"
link
:loading="false"
:disabled="scope.row.capitalState === CapitalInfoState.CLOSED"
@click="onDeleteClick(scope.row.id)"
>删除</BasePreventReClickButton
>
</template>
</el-table-column>
</el-table>
应用效果:



主要修改点:
1、添加 @expand-change 事件监听
@expand-change="onExpandChange"
// 资金信息表格行展开
const onExpandChange = async (row: CapitalInfo, expandedRows: CapitalInfo[]) => {
// 如果是展开操作,检查当前点击的行是否已经在展开的行数组中
if (expandedRows.some((expandedRow) => expandedRow.id === row.id)) {
// 获取资金分配明细列表
await capitalInfoStore.getCapitalAllocateDetailList(row);
}
};
2、添加 row-key 属性
:row-key="getRowKey"
// 获取展开行的key
const getRowKey = (row: CapitalInfo) => {
return String(row.id);
};
expandedRows.some((expandedRow) => expandedRow.id === row.id) 这行代码的意思是:
检查当前点击的行是否已经在展开的行数组中
让我详细解释一下:
代码分析
javascript
expandedRows.some((expandedRow) => expandedRow.id === row.id)
各部分的含义:
expandedRows:
-
这是 Element Plus 表格的 expand-change 事件返回的第二个参数
-
它是一个数组,包含了当前所有已展开的行数据
-
每次展开或收起行时,这个数组都会更新
.some() 方法:
-
这是 JavaScript 数组的原生方法
-
它会遍历数组中的每个元素,对每个元素执行提供的函数
-
如果有任意一个元素使函数返回 true,则整个 .some() 方法返回 true
-
如果所有元素都返回 false,则返回 false
箭头函数 (expandedRow) => expandedRow.id === row.id:
-
对 expandedRows 数组中的每个元素(每行数据)执行这个判断
-
检查当前遍历的已展开行(expandedRow)的 id 是否等于当前操作行(row)的 id
整体逻辑:
-
返回 true:表示当前点击的行(row)已经在已展开的行数组(expandedRows)中
-
说明这次点击是收起操作(因为行已经展开,再点就是收起)
-
-
返回 false:表示当前点击的行(row)不在已展开的行数组(expandedRows)中
-
说明这次点击是展开操作(因为行之前没展开,现在是第一次展开)
-
在你的场景中的应用
在你的代码中,这个判断被用来决定是否应该加载数据:
javascript
const onExpandChange = async (row: CapitalInfo, expandedRows: CapitalInfo[]) => {
// 如果是展开操作
if (expandedRows.some(expandedRow => expandedRow.id === row.id)) {
// 这个条件为 true,说明 row 在 expandedRows 中
// 表示当前是展开状态(点击后行被展开了)
// 执行加载数据的逻辑…
}
// 如果为 false,说明是收起操作,不执行加载逻辑
};
实际例子
假设:
-
row = {id: 123, capitalNo: "ABC001", …}
-
expandedRows = [{id: 456, …}, {id: 123, …}, {id: 789, …}]
那么:
javascript
expandedRows.some(expandedRow => expandedRow.id === row.id)
// 遍历 expandedRows:
// 1. expandedRow.id = 456,与 123 不相等 → false
// 2. expandedRow.id = 123,与 123 相等 → true
// 找到匹配项,立即返回 true
// 结果:true → 说明 ID 为 123 的行已经展开
可视化理解
text
时间轴:
1. 初始状态:expandedRows = [] (空数组,没有展开的行)
点击行 123 的展开图标 →
expandedRows = [{id: 123, …}] (行 123 被展开)
判断结果:true (是新展开的操作)
2. 当前状态:expandedRows = [{id: 123, …}, {id: 456, …}]
再次点击行 123 的展开图标 →
expandedRows = [{id: 456, …}] (行 123 被收起)
判断结果:false (是收起操作)
3. 点击行 789 →
expandedRows = [{id: 456, …}, {id: 789, …}]
判断结果:true (是新展开的操作)
这样设计的目的是:只在展开行时加载数据,收起行时不执行任何操作,避免不必要的网络请求和性能开销。
展开行表格如何增加加载状态?
为了给展开行的表格增加加载状态,你可以使用以下方案:
方案一:使用单独的加载状态变量(推荐)
vue
<script setup lang="ts">
import { ref, reactive } from 'vue';
// 定义加载状态映射
const expandLoading = reactive<Record<number, boolean>>({});
// 展开行变化时的处理
const onExpandChange = async (row: CapitalInfo, expandedRows: CapitalInfo[]) => {
// 如果是展开操作
if (expandedRows.some(expandedRow => expandedRow.id === row.id)) {
// 设置当前行的加载状态
expandLoading[row.id] = true;
try {
// 如果当前行不是已选中的行,则执行行点击逻辑
if (row.id !== capitalInfoStore.currentSelectedCapitalInfo?.id) {
await onRowClick(row);
} else {
// 如果已经是当前选中的行,确保明细列表已加载
await capitalInfoStore.getCapitalAllocateDetailList(row.id);
}
} finally {
// 无论成功还是失败,都清除加载状态
expandLoading[row.id] = false;
}
} else {
// 如果是收起操作,清除加载状态(如果需要的话)
expandLoading[row.id] = false;
}
};
// 获取行的展开状态(用于自定义展开图标)
const getExpandLoading = (row: CapitalInfo) => {
return expandLoading[row.id] || false;
};
</script>
<template>
<!– 资金信息列表 –>
<el-table
ref="capitalInfoTableRef"
:data="capitalInfoStore.capitalInfoList"
v-loading="capitalInfoStore.capitalInfoLoading"
highlight-current-row
stripe
:border="isBorder"
style="height: 100%"
@header-dragend="setTableColumnWidth?.saveColumnWidth"
@row-click="onRowClick"
@expand-change="onExpandChange"
:row-key="getRowKeys">
<!– 展开列 –>
<el-table-column type="expand" width="48" fixed="left">
<template #default="scope">
<!– 使用作用域插槽获取当前行数据 –>
<div v-if="scope.row.capitalAllocateDetailList?.length">
<el-table
:data="scope.row.capitalAllocateDetailList"
v-loading="getExpandLoading(scope.row)"
element-loading-text="加载中…"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(255, 255, 255, 0.7)">
<!– 表格列保持不变 –>
<el-table-column prop="index" label="" width="48" show-overflow-tooltip />
<el-table-column prop="deptName" label="指标使用部门" width="315" show-overflow-tooltip />
<el-table-column prop="total" label="指标分配金额" width="125" show-overflow-tooltip />
<el-table-column prop="budget" label="预算情况" width="125" show-overflow-tooltip />
<el-table-column prop="payType" label="支出分类" width="125" show-overflow-tooltip />
<el-table-column prop="payMode" label="支出方式" width="125" show-overflow-tooltip />
<el-table-column prop="validTotal" label="当前可使用额" width="120" show-overflow-tooltip />
<el-table-column prop="assistDeptName" label="协助部门" min-width="250" show-overflow-tooltip />
</el-table>
</div>
<div v-else style="text-align: center; padding: 20px; color: #909399;">
<span v-if="getExpandLoading(scope.row)">
<el-icon class="is-loading"><Loading /></el-icon> 加载中…
</span>
<span v-else>
暂无分配明细数据
</span>
</div>
</template>
</el-table-column>
<!– 数据列 –>
<!– 保持原有列不变 –>
</el-table>
</template>
方案二:在 store 中管理加载状态(如果使用 Pinia)
如果使用了 Pinia 管理状态,可以在 store 中管理展开行的加载状态:
typescript
// store/capitalInfoStore.ts
export const useCapitalInfoStore = defineStore('capitalInfo', {
state: () => ({
// 其他状态…
expandLoading: {} as Record<number, boolean>,
}),
actions: {
async getCapitalAllocateDetailList(id: number) {
// 开始加载
this.expandLoading[id] = true;
try {
// 调用API获取数据
const response = await api.getCapitalAllocateDetailList(id);
// 更新对应行的数据
const index = this.capitalInfoList.findIndex(item => item.id === id);
if (index !== -1) {
this.capitalInfoList[index].capitalAllocateDetailList = response.data;
}
} catch (error) {
console.error('加载分配明细失败:', error);
} finally {
// 结束加载
this.expandLoading[id] = false;
}
},
},
});
方案三:使用自定义展开图标显示加载状态
vue
<script setup lang="ts">
// 使用自定义展开图标显示加载状态
import { Loading } from '@element-plus/icons-vue';
// 检查行是否正在加载
const isRowLoading = (row: CapitalInfo) => {
return expandLoading[row.id] || false;
};
</script>
<template>
<el-table
<!– 其他属性保持不变 –>
>
<!– 展开列 –>
<el-table-column type="expand" width="48" fixed="left">
<template #header>
<span>明细</span>
</template>
<template #default="scope">
<!– 展开内容,同方案一 –>
</template>
</el-table-column>
<!– 在表格行中添加加载状态显示 –>
<el-table-column label="" width="80" fixed="left">
<template #default="scope">
<el-icon v-if="isRowLoading(scope.row)" class="is-loading">
<Loading />
</el-icon>
<span v-else>▶</span>
</template>
</el-table-column>
<!– 其他数据列 –>
</el-table>
</template>
<style scoped>
.is-loading {
animation: rotating 2s linear infinite;
}
@keyframes rotating {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
方案四:使用骨架屏增强体验
vue
<template>
<el-table-column type="expand" width="48" fixed="left">
<template #default="scope">
<div v-if="getExpandLoading(scope.row)">
<!– 骨架屏加载效果 –>
<div class="skeleton-container">
<el-skeleton :rows="5" animated />
</div>
</div>
<div v-else-if="scope.row.capitalAllocateDetailList?.length">
<!– 正常显示表格 –>
<el-table :data="scope.row.capitalAllocateDetailList">
<!– 表格列 –>
</el-table>
</div>
<div v-else style="text-align: center; padding: 20px; color: #909399;">
暂无分配明细数据
</div>
</template>
</el-table-column>
</template>
<style scoped>
.skeleton-container {
padding: 20px;
}
</style>
推荐方案
我推荐使用方案一,原因如下:
简单易用:不需要修改 store 结构
响应式:使用 reactive 对象管理状态,自动响应变化
精确控制:每行的加载状态独立管理
健壮性:使用 try…finally 确保加载状态被清除
关键点说明:
expandLoading 对象:
-
使用 Record<number, boolean> 类型,以行ID为键,加载状态为值
-
每行的加载状态独立管理,互不影响
try…finally 结构:
-
确保无论加载成功还是失败,都会清除加载状态
-
避免加载状态卡在 true 的情况
模板中的使用:
-
在嵌套表格上使用 v-loading="getExpandLoading(scope.row)"
-
在无数据时也显示加载状态,提升用户体验
性能考虑:
-
只对当前展开的行设置加载状态
-
收起行时清除对应的加载状态,避免内存泄漏
这种实现方式既保持了良好的用户体验,又保证了代码的清晰和可维护性。
增加展开状态的代码:
// 展开加载状态映射
const expandLoading = reactive<Record<number, boolean>>({});
// 资金信息表格行展开
const onExpandChange = async (row: CapitalInfo, expandedRows: CapitalInfo[]) => {
// 如果是展开操作,检查当前点击的行是否已经在展开的行数组中
if (expandedRows.some((expandedRow) => expandedRow.id === row.id)) {
try {
// 设置当前展开加载状态
expandLoading[row.id] = true;
// 获取资金分配明细列表
await capitalInfoStore.getCapitalAllocateDetailList(row);
} finally {
// 清除当前展开加载状态
expandLoading[row.id] = false;
}
}
};
<!– 展开列 –>
<el-table-column type="expand" width="48" fixed="left">
<template #default="scope">
<div v-if="scope.row.capitalAllocateDetailList?.length || expandLoading[scope.row.id]">
<el-table :data="scope.row.capitalAllocateDetailList" v-loading="expandLoading[scope.row.id]">
<el-table-column prop="index" label="" width="48" show-overflow-tooltip />
<el-table-column prop="deptName" label="指标使用部门" width="315" show-overflow-tooltip />
<el-table-column prop="total" label="指标分配金额" width="125" show-overflow-tooltip />
<el-table-column prop="budget" label="预算情况" width="125" show-overflow-tooltip />
<el-table-column prop="payType" label="支出分类" width="125" show-overflow-tooltip />
<el-table-column prop="payMode" label="支出方式" width="125" show-overflow-tooltip />
<el-table-column prop="validTotal" label="当前可使用额" width="120" show-overflow-tooltip />
<el-table-column prop="assistDeptName" label="协助部门" min-width="250" show-overflow-tooltip />
</el-table>
</div>
<div v-else style="text-align: center; padding: 10px">暂无数据</div>
</template>
</el-table-column>
如何设置展开行表格的背景颜色?
你可以通过多种方式为展开行表格设置背景颜色。以下是几种常见的方法:
方法一:直接在展开行容器上设置样式
vue
<template>
<el-table
<!– 其他属性保持不变 –>
>
<!– 展开列 –>
<el-table-column type="expand" width="48" fixed="left">
<template #default="scope">
<div class="expand-table-container">
<el-table
:data="scope.row.capitalAllocateDetailList"
v-loading="getExpandLoading(scope.row)"
class="expand-table"
:header-cell-class-name="expandTableHeaderClassName"
:row-class-name="expandTableRowClassName">
<!– 表格列保持不变 –>
<el-table-column prop="index" label="" width="48" show-overflow-tooltip />
<el-table-column prop="deptName" label="指标使用部门" width="315" show-overflow-tooltip />
<el-table-column prop="total" label="指标分配金额" width="125" show-overflow-tooltip />
<el-table-column prop="budget" label="预算情况" width="125" show-overflow-tooltip />
<el-table-column prop="payType" label="支出分类" width="125" show-overflow-tooltip />
<el-table-column prop="payMode" label="支出方式" width="125" show-overflow-tooltip />
<el-table-column prop="validTotal" label="当前可使用额" width="120" show-overflow-tooltip />
<el-table-column prop="assistDeptName" label="协助部门" min-width="250" show-overflow-tooltip />
</el-table>
</div>
</template>
</el-table-column>
<!– 其他列… –>
</el-table>
</template>
<style scoped>
/* 展开行容器样式 */
.expand-table-container {
background-color: #f8f9fa; /* 浅灰色背景 */
padding: 0; /* 移除默认内边距 */
margin: 0; /* 移除默认外边距 */
}
/* 嵌套表格整体样式 */
.expand-table {
/* 移除表格默认边框,使背景色更统一 */
–el-table-border-color: transparent;
–el-table-bg-color: transparent;
–el-table-header-bg-color: #e9ecef; /* 表头背景色 */
–el-table-row-hover-bg-color: #dee2e6; /* 行悬浮背景色 */
–el-table-header-text-color: #212529; /* 表头文字颜色 */
/* 表格背景透明,让容器背景色显示 */
background-color: transparent !important;
}
/* 使用深度选择器修改嵌套表格的样式 */
:deep(.expand-table) {
/* 表头样式 */
.el-table__header-wrapper {
background-color: #e9ecef;
}
/* 表头单元格样式 */
.el-table__header th {
background-color: #e9ecef !important;
color: #212529;
font-weight: 600;
border-bottom: 1px solid #ced4da;
}
/* 表格主体行样式 */
.el-table__body tr {
background-color: #f8f9fa; /* 行背景色 */
}
/* 表格主体行悬停样式 */
.el-table__body tr:hover > td {
background-color: #dee2e6 !important;
}
/* 交替行背景色 */
.el-table__body tr.el-table__row–striped {
background-color: #f1f3f5 !important;
}
/* 表格单元格样式 */
.el-table__body td {
border-bottom: 1px solid #e9ecef;
}
/* 表格边框样式 */
.el-table–border {
border: 1px solid #dee2e6;
}
.el-table–border td,
.el-table–border th {
border-right: 1px solid #dee2e6;
}
}
/* 表头单元格类名函数 */
const expandTableHeaderClassName = ({ rowIndex }: { rowIndex: number }) => {
return 'expand-table-header';
};
/* 表格行类名函数 */
const expandTableRowClassName = ({ rowIndex }: { rowIndex: number }) => {
// 偶数行添加浅色背景,奇数行保持默认
return rowIndex % 2 === 0 ? 'expand-table-row-even' : 'expand-table-row-odd';
};
</style>
方法二:使用斑马纹和自定义行样式
vue
<script setup lang="ts">
// 展开行表格的斑马纹和行样式函数
const getExpandRowClassName = ({ rowIndex }: { rowIndex: number }) => {
const classes: string[] = [];
// 添加斑马纹类
if (rowIndex % 2 === 1) {
classes.push('expand-row-stripe');
}
// 根据数据状态添加特定类
// 例如:如果金额为负,添加警告类
// if (row.validTotal < 0) {
// classes.push('expand-row-warning');
// }
return classes.join(' ');
};
</script>
<template>
<el-table-column type="expand" width="48" fixed="left">
<template #default="scope">
<div class="expand-content-wrapper">
<el-table
:data="scope.row.capitalAllocateDetailList"
:row-class-name="getExpandRowClassName"
stripe
border
class="expand-detail-table">
<!– 表格列 –>
</el-table>
</div>
</template>
</el-table-column>
</template>
<style scoped>
.expand-content-wrapper {
background: linear-gradient(to bottom, #ffffff, #f8f9fa);
padding: 16px;
border-radius: 8px;
margin: 8px;
}
.expand-detail-table {
/* 表格整体样式 */
–el-table-border-color: #dee2e6;
–el-table-bg-color: #ffffff;
–el-table-header-bg-color: #f1f5f9;
–el-table-row-hover-bg-color: #f8fafc;
}
/* 斑马纹行样式 */
:deep(.expand-detail-table .el-table__row.expand-row-stripe) {
background-color: #f8fafc !important;
}
/* 悬停效果 */
:deep(.expand-detail-table .el-table__row:hover) {
background-color: #f1f5f9 !important;
}
/* 表头样式 */
:deep(.expand-detail-table .el-table__header) {
background-color: #f1f5f9;
}
:deep(.expand-detail-table .el-table__header th) {
background-color: #f1f5f9 !important;
color: #334155;
font-weight: 600;
}
</style>
方法三:使用CSS变量动态控制(Vue 3.2+)
vue
<script setup lang="ts">
import { ref } from 'vue';
// 定义可配置的背景颜色
const expandTableConfig = ref({
headerBgColor: '#e9ecef',
rowBgColor: '#f8f9fa',
stripeBgColor: '#f1f3f5',
hoverBgColor: '#dee2e6',
borderColor: '#dee2e6',
textColor: '#212529',
headerTextColor: '#212529'
});
</script>
<template>
<el-table-column type="expand" width="48" fixed="left">
<template #default="scope">
<div
class="expand-table-wrapper"
:style="{
'–header-bg-color': expandTableConfig.headerBgColor,
'–row-bg-color': expandTableConfig.rowBgColor,
'–stripe-bg-color': expandTableConfig.stripeBgColor,
'–hover-bg-color': expandTableConfig.hoverBgColor,
'–border-color': expandTableConfig.borderColor,
'–text-color': expandTableConfig.textColor,
'–header-text-color': expandTableConfig.headerTextColor
}">
<el-table
:data="scope.row.capitalAllocateDetailList"
class="dynamic-expand-table"
stripe>
<!– 表格列 –>
</el-table>
</div>
</template>
</el-table-column>
</template>
<style scoped>
.expand-table-wrapper {
padding: 12px;
background-color: var(–row-bg-color);
border-radius: 6px;
margin: 4px;
}
:deep(.dynamic-expand-table) {
/* 使用CSS变量 */
–el-table-border-color: var(–border-color);
–el-table-header-bg-color: var(–header-bg-color);
–el-table-row-hover-bg-color: var(–hover-bg-color);
background-color: transparent;
}
:deep(.dynamic-expand-table .el-table__header-wrapper) {
background-color: var(–header-bg-color);
}
:deep(.dynamic-expand-table .el-table__header th) {
background-color: var(–header-bg-color) !important;
color: var(–header-text-color) !important;
font-weight: 600;
}
:deep(.dynamic-expand-table .el-table__body tr) {
background-color: var(–row-bg-color);
color: var(–text-color);
}
:deep(.dynamic-expand-table .el-table__row–striped) {
background-color: var(–stripe-bg-color) !important;
}
:deep(.dynamic-expand-table .el-table__row:hover > td) {
background-color: var(–hover-bg-color) !important;
}
</style>
方法四:根据数据状态动态设置行背景色
vue
<script setup lang="ts">
// 根据数据动态设置行背景色
const getExpandRowStyle = (row: any, rowIndex: number) => {
const style: Record<string, any> = {};
// 根据预算情况设置背景色
if (row.budget && row.budget.includes('超支')) {
style.backgroundColor = '#fff5f5'; // 浅红色,表示超支
style.color = '#c92a2a';
} else if (row.validTotal <= 0) {
style.backgroundColor = '#fff9db'; // 浅黄色,表示余额不足
style.color = '#e67700';
} else if (row.validTotal < row.total * 0.2) {
style.backgroundColor = '#fff3bf'; // 浅黄色,表示余额较少
style.color = '#f08c00';
}
return style;
};
</script>
<template>
<el-table-column type="expand" width="48" fixed="left">
<template #default="scope">
<el-table
:data="scope.row.capitalAllocateDetailList"
:row-style="getExpandRowStyle"
class="status-based-table">
<!– 表格列 –>
</el-table>
</template>
</el-table-column>
</template>
<style scoped>
:deep(.status-based-table) {
background-color: #ffffff;
}
:deep(.status-based-table .el-table__header) {
background-color: #f8f9fa;
}
/* 特定状态行的悬停效果 */
:deep(.status-based-table .el-table__row:hover > td) {
opacity: 0.9;
}
</style>
方法五:使用预定义的CSS类
vue
<template>
<el-table-column type="expand" width="48" fixed="left">
<template #default="scope">
<el-table
:data="scope.row.capitalAllocateDetailList"
class="expand-table-custom">
<!– 表格列 –>
</el-table>
</template>
</el-table-column>
</template>
<style scoped>
/* 预定义的主题类 */
.expand-table-custom {
/* 浅色主题 */
&.theme-light {
–el-table-header-bg-color: #f1f5f9;
–el-table-bg-color: #ffffff;
–el-table-row-hover-bg-color: #f8fafc;
}
/* 深色主题 */
&.theme-dark {
–el-table-header-bg-color: #334155;
–el-table-bg-color: #1e293b;
–el-table-row-hover-bg-color: #475569;
color: #f8fafc;
}
/* 蓝色主题 */
&.theme-blue {
–el-table-header-bg-color: #dbeafe;
–el-table-bg-color: #eff6ff;
–el-table-row-hover-bg-color: #dbeafe;
}
}
:deep(.expand-table-custom) {
background-color: var(–el-table-bg-color);
.el-table__header-wrapper {
background-color: var(–el-table-header-bg-color);
}
.el-table__header th {
background-color: var(–el-table-header-bg-color) !important;
}
.el-table__body tr:hover > td {
background-color: var(–el-table-row-hover-bg-color) !important;
}
}
</style>
推荐方案
对于你的资金管理系统,我推荐使用方法一或方法二:
-
方法一提供了最全面的控制,可以自定义所有样式细节
-
方法二使用了Element Plus内置的斑马纹功能,代码更简洁
简洁版推荐(使用方法二):
vue
<template>
<el-table-column type="expand" width="48" fixed="left">
<template #default="scope">
<div class="expand-table-wrapper">
<el-table
:data="scope.row.capitalAllocateDetailList"
stripe
border
class="nested-capital-table"
style="background-color: #f8f9fa;">
<!– 表格列 –>
</el-table>
</div>
</template>
</el-table-column>
</template>
<style scoped>
.expand-table-wrapper {
background-color: #f8f9fa;
padding: 8px;
}
/* 如果需要更精细的控制,使用深度选择器 */
:deep(.nested-capital-table) {
–el-table-border-color: #dee2e6;
–el-table-header-bg-color: #e9ecef;
–el-table-row-hover-bg-color: #dee2e6;
}
:deep(.nested-capital-table .el-table__header th) {
background-color: #e9ecef !important;
font-weight: 600;
}
</style>
关键提示:
使用 :deep() 深度选择器:因为Element Plus的表格组件使用了作用域样式,需要使用深度选择器来修改内部元素的样式。
CSS变量:Element Plus提供了一系列CSS变量来定制表格样式,可以直接使用。
避免使用 !important:虽然示例中使用了,但尽量通过提高选择器特异性来避免。
保持一致性:展开行表格的样式应与主表格的样式协调一致。
选择哪种方法取决于你的具体需求和设计规范。如果只是简单的背景色设置,使用内联样式或简单的CSS类即可;如果需要复杂的效果或动态样式,可以使用更高级的方法。
增加展开表格样式设置代码:
<!– 展开列 –>
<el-table-column type="expand" width="48" fixed="left">
<template #default="scope">
<div v-if="scope.row.capitalAllocateDetailList?.length || expandLoading[scope.row.id]">
<el-table
class="expand-table"
:data="scope.row.capitalAllocateDetailList"
v-loading="expandLoading[scope.row.id]">
<el-table-column prop="index" label="" width="48" show-overflow-tooltip />
<el-table-column prop="deptName" label="指标使用部门" width="315" show-overflow-tooltip />
<el-table-column prop="total" label="指标分配金额" width="125" show-overflow-tooltip />
<el-table-column prop="budget" label="预算情况" width="125" show-overflow-tooltip />
<el-table-column prop="payType" label="支出分类" width="125" show-overflow-tooltip />
<el-table-column prop="payMode" label="支出方式" width="125" show-overflow-tooltip />
<el-table-column prop="validTotal" label="当前可使用额" width="120" show-overflow-tooltip />
<el-table-column prop="assistDeptName" label="协助部门" min-width="250" show-overflow-tooltip />
</el-table>
</div>
<div v-else style="text-align: center; padding: 10px; background-color: #f8f9fa">暂无数据</div>
</template>
</el-table-column>
/* 展开表格整体样式 */
.expand-table {
/* 移除表格默认边框,使背景色更统一 */
// –el-table-border-color: transparent;
// –el-table-bg-color: transparent;
// –el-table-header-bg-color: #e9ecef; /* 表头背景色 */
// –el-table-row-hover-bg-color: #dee2e6; /* 行悬浮背景色 */
// –el-table-header-text-color: #212529; /* 表头文字颜色 */
/* 表格背景透明,让容器背景色显示 */
background-color: transparent !important;
}
/* 使用深度选择器修改展开表格的样式 */
:deep(.expand-table) {
/* 表头样式 */
.el-table__header-wrapper {
background-color: #e9ecef;
}
/* 表头单元格样式 */
.el-table__header th {
background-color: #e9ecef !important;
// color: #212529;
// font-weight: 600;
border-bottom: 1px solid #ced4da;
}
/* 表格主体行样式 */
.el-table__body tr {
background-color: #f8f9fa; /* 行背景色 */
}
/* 表格主体行悬停样式 */
.el-table__body tr:hover > td {
background-color: #dee2e6 !important;
}
/* 交替行背景色 */
.el-table__body tr.el-table__row–striped {
background-color: #f1f3f5 !important;
}
/* 表格单元格样式 */
.el-table__body td {
border-bottom: 1px solid #e9ecef;
}
}
应用效果:







