1、实现一个树形和末级展开是表格,需要支持大数据量,因此使用Virtualized Table 虚拟化表格 el-table-v2
2、效果图
3、代码
<template> <el-table-v2 :header-height="0" v-model:expanded-row-keys="expandedRowKeys" :columns="columns" :data="treeData" :width="1000" :expand-column-key="expandColumnKey" :height="800" :estimated-row-height="200" @row-expand="onRowExpanded" @expanded-rows-change="onExpandedRowsChange"> <template #row="props"> <Row v-bind="props" /> <div class="p-6" v-if="!props.rowData.children.length"> <el-table :data="props.rowData.tableData" :height="200" style="width: 100%" border header-cell-class-name="table-header"> <el-table-column prop="name" label="文件名称" /> <el-table-column prop="size" label="文件大小" /> <el-table-column prop="date" label="上传日期" /> <el-table-column align="center" label="操作" width="80" > <template #default="scope"> <el-icon @click="handleDownload(scope.$index, scope.row)"><Download /></el-icon> </template> </el-table-column> </el-table> </div> <div style="height: 50px;line-height: 50px;margin-left: 5px;"> <el-button v-if="props.rowData.children.length" :icon="Download" type="primary" plain @click="handleDownload(null, props.rowData)" >下载目录</el-button> </div> </template> </el-table-v2> </template> <script setup> import { computed, ref, createVNode as _createVNode2 } from 'vue' import { TableV2FixedDir } from 'element-plus' import {Download} from '@element-plus/icons-vue' const expandColumnKey = 'column-0' const generateColumns = (length = 10, prefix = 'column-', props) => Array.from({ length }).map((_, columnIndex) => ({ ...props, key: `${prefix}${columnIndex}`, dataKey: `${prefix}${columnIndex}`, title: `Column ${columnIndex}` })) const generateData = ( columns, length = 200, prefix = 'row-' ) => Array.from({ length }).map((_, rowIndex) => { return columns.reduce( (rowData, column, columnIndex) => { rowData[column.dataKey] = `文件文件文件文件文件${rowIndex}` return rowData }, { id: `${prefix}${rowIndex}`, parentId: null, } ) }) const columns = generateColumns(1).map((column, columnIndex) => { let fixed return { ...column, fixed } }) const data = generateData(columns, 200) for (let i = 0; i < 200; i++) { data.push( { ...data[i], id: `${data[i].id}-sub-${i}`, parentId: data[i].id, [expandColumnKey]: `202${i}`, },{ ...data[i], id: `${data[i].id}-sub-sub-${i}`, parentId: `${data[i].id}-sub-${i}`, [expandColumnKey]: `Sub-202${i}`, } ) } function unflatten( data, rootId = null, dataKey = 'id', parentKey = 'parentId' ) { const tree = [] const childrenMap = {} for (const datum of data) { const item = { ...datum } const id = item[dataKey] const parentId = item[parentKey] if (Array.isArray(item.children)) { childrenMap[id] = item.children.concat(childrenMap[id] || []) } else if (!childrenMap[id]) { childrenMap[id] = [] } item.children = childrenMap[id] if(!item.children.length){ item.tableData = [ { date: '2016-05-03', name: 'Tom', size: '18kb', }, { date: '2016-05-02', name: 'Tom', size: '18kb', }, { date: '2016-05-04', name: 'Tom', size: '18kb', }, { date: '2016-05-01', name: 'Tom', size: '108kb', } ] } if (parentId !== undefined && parentId !== rootId) { if (!childrenMap[parentId]) childrenMap[parentId] = [] childrenMap[parentId].push(item) } else { tree.push(item) } } return tree } const treeData = computed(() => unflatten(data)) const expandedRowKeys = ref([]) const onRowExpanded = ({ expanded }) => { console.log('Expanded:', expanded) } const onExpandedRowsChange = ( expandedKeys ) => { console.log(expandedKeys) } const Row = ({ cells, rowData }) => { if (rowData.children.length) { return cells; } } const handleDownload = (index, row) => { console.log(index, row) } </script> <style> .el-table-v2{ --el-table-border-color:none; } .el-table-v2__row-depth-0, .el-table-v2__row-depth-1, .el-table-v2__row-depth-2, .el-table-v2__row-depth-3, .el-table-v2__row-depth-4, .el-table-v2__row-depth-5, .el-table-v2__row-depth-6 { min-height: 50px; } .el-table-v2__row-cell{ width: fit-content !important; } .el-table-v2__cell-text{ height: 32px; min-width: 100px; line-height: 32px;; background-color: #F7F8FC; border: var(--el-border); border-color: #dcdfe6; padding: 0 15px; font-size: var(--el-font-size-base); border-radius: var(--el-border-radius-base); margin-top: 1px; } .el-table-v2__cell-text:hover { color: #409eff; border-color: #409eff; background-color: #ecf5ff; } .el-table-v2__cell-text::before { content: ''; /* position: absolute; */ display: inline-block; width: 16px; height: 16px; margin-right: 5px; vertical-align: text-top; background-image: url('data:image/svg+xml;utf8,<svg data-v-d2e47025="" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path fill="grey" d="M878.08 448H241.92l-96 384h636.16l96-384zM832 384v-64H485.76L357.504 192H128v448l57.92-231.744A32 32 0 0 1 216.96 384zm-24.96 512H96a32 32 0 0 1-32-32V160a32 32 0 0 1 32-32h287.872l128.384 128H864a32 32 0 0 1 32 32v96h23.04a32 32 0 0 1 31.04 39.744l-112 448A32 32 0 0 1 807.04 896"></path></svg>'); /* 替换为你的 SVG Data URI */ background-size: cover; /* 确保 SVG 图像覆盖整个伪元素区域 */ } .el-table-v2__cell-text:hover::before { background-image: url('data:image/svg+xml;utf8,<svg data-v-d2e47025="" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path fill="CornflowerBlue" d="M878.08 448H241.92l-96 384h636.16l96-384zM832 384v-64H485.76L357.504 192H128v448l57.92-231.744A32 32 0 0 1 216.96 384zm-24.96 512H96a32 32 0 0 1-32-32V160a32 32 0 0 1 32-32h287.872l128.384 128H864a32 32 0 0 1 32 32v96h23.04a32 32 0 0 1 31.04 39.744l-112 448A32 32 0 0 1 807.04 896"></path></svg>'); /* 替换为你的 SVG Data URI */ } .p-6 { margin:0 20px; width: 98%; height:200px; } .el-button:focus, .el-button:hover { color: var(--el-button-text-color); border-color: var(--el-button-hover-border-color); background-color: #ecf5ff; outline: 0; } .table-header{ background-color: #F8F9FB !important; } </style>
标签:el,const,element,v2,plus,table,末级,data,id From: https://www.cnblogs.com/aoshuang/p/18539298