欢迎光临
我们一直在努力

Vue3+Element-Plus+ELTable实现展开行加载从表列表数据

原来的代码:

// 资金信息表格行点击
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;
    }
    }

    应用效果:

    赞(0)
    未经允许不得转载:171主机测评 » Vue3+Element-Plus+ELTable实现展开行加载从表列表数据
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址