当前位置: 首页 > news >正文

基于 elements3 包装的 可展开 table 组件

基于 elements3 包装的 可展开 table 组件

1.手风琴效果,一次只能展开一个

2.动态加载 展开内容 (根据接口)

效果:

<template><el-tableref="tableRef":data="tableData"v-loading="loading"v-if="columns.length > 0"style="width: 100%"@expand-change="handleExpand"class="custom-expend-table"header-row-class-name="custom-table-header"row-class-name="custom-table-row"@row-click="handleClick"><!-- 折叠列 --><el-table-column type="expand" v-if="hasExpand" width="20"><template #default="{ row }"><div class="expand-content-wrapper"><el-tablev-if="childDataMap[row[rowKey]]?.length":data="childDataMap[row[rowKey]]"size="small"header-row-class-name="child-table-header"row-class-name="child-table-row"><el-table-columnv-for="col in childColumns":key="col.column":label="col.showName":prop="col.column":min-width="col.width || col.column === 'month' ? 50 : 80"align="center"><template #default="{ row }">{{ row[col.column] || '-' }}</template></el-table-column></el-table><div v-else class="text-gray-500 text-center py-4 empty-box">{{ expandLoadingMap[row[rowKey]] ? '加载中...' : '暂无数据' }}</div></div></template></el-table-column><!-- 主表列 --><el-table-columnv-for="col in columns":key="col.column":prop="col.column":label="col.showName":min-width="col.width || col.column === 'year' ? 50 : 80"align="center"><template #default="{ row }">{{ row[col.column] || '-' }}</template></el-table-column><template #empty><EmptyBox desc="无数据" v-if="height" :height="'auto'" /><EmptyBox desc="无数据" v-else /></template></el-table>
</template><script setup lang="ts">
import { ref , PropType,computed } from 'vue'
import { ElMessage } from 'element-plus'
import {sortByDate} from "@/utils/formate/sort_formate";
import { isEqual  } from 'lodash-es';const props = defineProps({height: {type: [String, Boolean],default: '180'},tableData: {type: Array as PropType<any[]>,required: true,},columns: {type: Array as PropType<any[]>, // 使用定义好的 Column 类型required: true,}, // 主表字段rowKey: {type: String,default: 'id',},fetchChildData: {type: Function || Function as PropType<(row: any) => Promise<any>> ,required: false,default: undefined},loading: {type: Boolean,default: false,},isThrottle: {type: Boolean,default: false,}
})const hasExpand = computed(() => typeof props.fetchChildData === 'function')// 保存每行子表数据
const childDataMap = ref<Record<string, any[]>>({})
const childColumns = ref<any[]>([])
const expandLoadingMap = ref<Record<string, boolean>>({})// 展开行触发:异步加载子表
const handleExpand = async (row: any, expanded: any[]) => {const rowKey: any = row[props.rowKey]// 当前展开的 rowKey(row 点击后立即触发)const isExpanding: any = expanded.some((t: any) => rowKey == t[props.rowKey])// 收起时清空记录if (!isExpanding) {if (currentExpandedRowKey.value === rowKey) {currentExpandedRowKey.value = null}return}// 若当前点击的不是同一行,先收起上一个if (currentExpandedRowKey.value && currentExpandedRowKey.value !== rowKey) {const prevRow = props.tableData?.find((item: any) => item[props.rowKey] === currentExpandedRowKey.value)if (prevRow && tableRef.value) {tableRef.value.toggleRowExpansion(prevRow, false)}}// 设置当前展开行为当前行currentExpandedRowKey.value = rowKey// 判断是否需要加载数据if (props.isThrottle && childDataMap.value[rowKey]) returnexpandLoadingMap.value[rowKey] = truetry {if (!props.fetchChildData) returnconst { head, data } = await props.fetchChildData(row)sortByDate(data, 'month', 'desc')childDataMap.value[rowKey] = data || []childColumns.value = head || []} catch (err) {ElMessage.error('子表加载失败')childDataMap.value[rowKey] = []} finally {expandLoadingMap.value[rowKey] = false}
}const tableRef = ref()
const currentExpandedRowKey = ref<string | null>(null)
const currentExpandedRow = ref<any>(null)
const handleClick = (row: any) => {if (!hasExpand.value) returnconst rowKey = row[props.rowKey]// 从 tableData 中找到真正要展开的那一行(必要)const matchedRow: any = props.tableData?.find((item: any) => item[props.rowKey] === rowKey)if (!matchedRow) {console.warn('找不到匹配的行数据:', rowKey)return}// 👉 判断是否是“当前已展开的那一行”const isSameRow = (currentExpandedRowKey.value === rowKey &&isEqual(currentExpandedRow.value, matchedRow))// 如果点击的是当前已展开行 → 收起if ( isSameRow ) {tableRef.value.toggleRowExpansion(matchedRow, false)currentExpandedRowKey.value = nullcurrentExpandedRow.value = nullreturn}// 收起之前已展开的if (currentExpandedRowKey.value !== null) {const prevRow = props.tableData.find((item: any) => item[props.rowKey] === currentExpandedRowKey.value)if (prevRow) {tableRef.value.toggleRowExpansion(prevRow, false)}}// 展开新行tableRef.value.toggleRowExpansion(matchedRow, true)currentExpandedRowKey.value = rowKeycurrentExpandedRow.value = matchedRow
}defineExpose({handleClick,
});</script>

使用:

    <CustomExpandTableref="expandTable":columns="tableData.head":tableData="tableData.data":fetchChildData="getSubTable"rowKey="stattime"></CustomExpandTable>

http://www.dtcms.com/a/282342.html

相关文章:

  • Elasticsearch+Logstash+Filebeat+Kibana部署
  • 前端状态管理对比:Redux与Vuex的深度分析
  • 利用 Spring 的 `@Scheduled` 注解结合简单的状态跟踪实现空闲检测方案
  • Node.js Domain 模块深度解析与最佳实践
  • 玩转Docker | 使用Docker部署vnStat网络流量监控服务
  • WPF 导入自定义字体并实现按钮悬停高亮效果
  • 微软AutoGen:多智能体协作的工业级解决方案
  • PostGres超过最大连接数报错
  • Linux LVS集群技术详解与实战指南
  • 通信算法之292:大疆DJI云哨系统-DroneID物理层协议解析-O1/O2/O3/O4机型都可以CRC正确
  • Redisson
  • 【知识图谱】Neo4j桌面版运行不起来怎么办?Neo4j Desktop无法打开!
  • C++设计模式之创建型模式
  • Qt小组件 - 6 异步运行函数
  • 暑假---作业2
  • QT技巧之快速搭建串口收发平台
  • Qt中实现文件(文本文件)内容对比
  • Django基础(三)———模板
  • Python设计模式深度解析:装饰器模式(Decorator Pattern)完全指南
  • hadoop 集群问题处理
  • 肠道宏基因组数据分析流程
  • 肠道宏基因组数据分析流程要关注的参数和指标
  • STM32-RTC内部时钟
  • 图像质量评价(Image Quality Assessment,IQA)
  • 【unitrix】 6.1 类型化整数特征(t_int.rs)
  • 深入理解-Java-线程池:原理、动态调整与监控实践
  • 牛市看涨期权的价差策略是什么?
  • mongoDB初始化项目简单操作示例
  • YAML 自动化用例中 GET vs POST 请求的参数写法差异
  • 部分排序算法的Java模拟实现(复习向,非0基础)