恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

vxe-table树形表格两种实现方式与分页处理实战

  • 首页
  • 资讯中心
  • /
  • vxe-table树形表格两种实现方式与分页处理实战

相关资讯

OpenIM企业级IM服务部署与Vue3集成实战指南 2026/10/9 17:29:09
基于Vue和Spring Boot的超市进销存系统实战:库存设计、单据闭环与部署要点 2026/10/9 17:29:09
JS对象本质、高频操作与实战避坑:从键值对到深拷贝 2026/10/9 17:24:09

最新资讯

Bootstrap网站模板选型实战指南:可维护性与工程化交付
∑是什么意思?从求和符号到算法复杂度与机器学习应用全解析
T3 Stack 全栈开发实战:用类型安全贯通前后端
程序员必修的数理逻辑实战指南:从命题逻辑到可计算性
jSignature移动端横屏签名板源码解析与真机避坑指南
MVX架构模式全解析:从MVC到MVI的演进逻辑与选型指南

今日推荐

AI编程智能体实战:从写代码到指挥代码的架构与落地
多模态大模型全栈能力拆解:从数据对齐到弹性推理
大模型Agent开发入门:从工具调用循环到落地避坑指南

本周热门

MR25H40CDF + PIC18F65K40:工业记录仪高可靠存储实战
基于STM32的数控恒压恒流电源设计:从硬件到PID调参全解析
LT9211 MIPI重定时器原理与双路扇出实战指南

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

vxe-table树形表格两种实现方式与分页处理实战

发布时间:2026/10/9 17:29:09
vxe-table树形表格两种实现方式与分页处理实战 1. 树形表格的真实需求与场景拆解树形表格这个需求做过中后台系统的人应该都不陌生。组织架构管理、商品分类目录、权限菜单配置、多级审批流展示这些场景天然就是树形结构的数据但同时又需要以表格的形式呈现——因为表格能承载更多的字段信息比如每一级节点的状态、创建时间、负责人、操作按钮等等。普通的树形控件只能展示一个名称远远不够用。我在实际项目里遇到过好几次这种需求。最早的时候尝试用普通的树形控件硬撑结果字段一多就完全没法看后来换成表格自己手写展开折叠逻辑又踩了一堆坑。直到用上了vxe-table这个组件库才发现它原生就支持树形表格而且支持两种不同的实现方式还能配合分页使用。这篇文章就把这两种方式彻底讲清楚包括它们各自的适用场景、配置细节、踩坑经验以及分页场景下怎么处理。vxe-table是一个基于Vue的表格组件库功能非常全面在GitHub上有不少star。它的树形表格功能支持两种模式一种是树形数据结构模式也就是数据本身就是嵌套的children结构另一种是扁平数据父子ID关联模式数据是平铺的通过字段标识父子关系由组件内部自动转换成树形结构。这两种方式各有优劣选哪种取决于你的后端接口返回什么格式的数据以及你对性能的要求。这篇文章适合正在做中后台系统的前端开发者尤其是那些需要展示层级数据但又不想自己造轮子的同学。不管你是刚接触vxe-table的新手还是已经用过但没深入研究树形表格的老手应该都能从下面的内容里找到有用的东西。我会从设计思路、配置细节、实操步骤、分页处理、常见问题几个维度展开尽量把每个关键点都讲透。2. 两种实现方式的核心思路与选型对比2.1 为什么会有两种方式先说清楚为什么vxe-table要提供两种树形表格的实现方式。根本原因在于后端接口返回的数据结构不统一。有的后端团队习惯返回嵌套结构比如[ { id: 1, name: 一级节点A, children: [ { id: 11, name: 二级节点A-1, children: [] } ] } ]这种结构天然就是树前端拿到直接渲染就行。但有的后端团队习惯返回扁平结构比如[ { id: 1, name: 一级节点A, parentId: null }, { id: 11, name: 二级节点A-1, parentId: 1 }, { id: 12, name: 二级节点A-2, parentId: 1 } ]这种结构在数据库里存储更方便查询效率也更高但前端需要自己转换成树形。vxe-table考虑到这两种情况所以提供了两种配置方式。2.2 方式一嵌套children结构这种方式的核心配置是tree-config里的children字段。你只需要告诉表格哪个字段是子节点数组它就会自动递归渲染。配置大概长这样treeConfig: { children: children, expandAll: false, accordion: false }这种方式的优点是前端不需要做任何数据转换后端返回什么就直接渲染什么。缺点是如果树层级很深、节点很多递归渲染的性能会下降而且后端需要递归查询数据库接口响应时间可能比较长。2.3 方式二扁平数据父子ID关联这种方式的核心配置是tree-config里的transform和rowField、parentField。你需要告诉表格哪个字段是节点ID哪个字段是父节点ID组件内部会自动把扁平数据转换成树形结构。配置大概长这样treeConfig: { transform: true, rowField: id, parentField: parentId, expandAll: false }这种方式的优点是后端查询简单一次查询就能拿到所有数据前端转换的性能也比递归渲染要好。缺点是前端需要额外做一次转换而且如果数据量特别大转换本身也会消耗时间。2.4 两种方式的选型对照表对比维度嵌套children结构扁平数据父子ID后端返回格式嵌套JSON扁平数组前端数据转换不需要组件内部自动转换数据库查询需要递归查询一次查询即可渲染性能层级深时较差相对较好配置复杂度简单稍复杂适用场景数据量小、层级浅数据量大、层级深分页支持需要额外处理需要额外处理选哪种方式我的建议是如果后端接口已经返回了嵌套结构那就直接用方式一没必要再让后端改。如果后端返回的是扁平结构或者数据量比较大那就用方式二。如果后端还没定接口格式我建议用方式二因为扁平结构在数据库层面更友好前端转换的成本也可以接受。3. 嵌套children结构的完整实操3.1 基础配置与数据准备先来看方式一的完整实现。假设我们要做一个组织架构表格后端返回的数据是这样的const tableData [ { id: 1, name: 技术中心, manager: 张三, status: 正常, createTime: 2024-01-15, children: [ { id: 11, name: 前端组, manager: 李四, status: 正常, createTime: 2024-01-16, children: [ { id: 111, name: 前端一组, manager: 王五, status: 正常, createTime: 2024-01-17, children: [] } ] }, { id: 12, name: 后端组, manager: 赵六, status: 正常, createTime: 2024-01-16, children: [] } ] } ]表格的配置大概是这样// 表格列配置 const columns [ { field: name, title: 部门名称, treeNode: true, width: 250 }, { field: manager, title: 负责人, width: 120 }, { field: status, title: 状态, width: 100 }, { field: createTime, title: 创建时间, width: 150 } ] // 树形配置 const treeConfig { children: children, expandAll: false, accordion: false, trigger: default }这里有几个关键点需要说明。第一treeNode: true必须加在你要展示树形展开图标的列上通常就是名称列。第二children字段名要和后端返回的一致如果后端返回的是subItems那这里就要写subItems。第三expandAll控制是否默认展开所有节点如果数据量大建议设为false让用户自己展开。3.2 展开折叠的交互控制vxe-table提供了几种展开折叠的控制方式。accordion设为true时同一层级只能展开一个节点类似手风琴效果。trigger可以设为default点击图标展开或cell点击整行展开。我个人的经验是如果表格列比较多建议用default避免用户点击行的时候误触展开。另外你还可以通过表格实例的方法来动态控制展开状态// 展开所有节点 tableRef.value.setAllTreeExpand(true) // 折叠所有节点 tableRef.value.setAllTreeExpand(false) // 展开指定行 tableRef.value.setTreeExpand(row, true) // 判断某行是否已展开 const isExpanded tableRef.value.isTreeExpandByRow(row)这些方法在实际项目里很有用。比如用户点击“全部展开”按钮时就可以调用setAllTreeExpand(true)。需要注意的是如果数据是异步加载的要等数据加载完成后再调用这些方法否则可能不生效。3.3 异步加载子节点如果树形数据不是一次性返回的而是点击展开时才去请求子节点vxe-table也支持。配置里加上lazy: true和loadMethodconst treeConfig { children: children, lazy: true, loadMethod: async ({ row }) { const res await fetchChildren(row.id) return res.data } }这里有个坑要注意loadMethod返回的数据会直接作为当前行的children所以返回的数组里每个元素也要符合表格的数据结构。另外如果请求失败最好返回空数组避免组件内部报错。提示异步加载模式下expandAll配置无效因为子节点还没加载出来。如果需要默认展开第一级可以在数据加载完成后手动调用setTreeExpand。4. 扁平数据父子ID关联的完整实操4.1 数据格式与转换原理方式二的核心是transform配置。当transform: true时vxe-table会根据rowField和parentField自动把扁平数组转换成树形结构。假设后端返回的数据是这样的const flatData [ { id: 1, parentId: null, name: 技术中心, manager: 张三, status: 正常 }, { id: 11, parentId: 1, name: 前端组, manager: 李四, status: 正常 }, { id: 111, parentId: 11, name: 前端一组, manager: 王五, status: 正常 }, { id: 12, parentId: 1, name: 后端组, manager: 赵六, status: 正常 }, { id: 2, parentId: null, name: 产品中心, manager: 孙七, status: 正常 }, { id: 21, parentId: 2, name: 产品设计组, manager: 周八, status: 正常 } ]配置大概是这样const treeConfig { transform: true, rowField: id, parentField: parentId, expandAll: false, accordion: false }组件内部会做一次转换把parentId为null的作为根节点然后递归挂载子节点。转换后的结构和方式一的嵌套结构是一样的所以渲染逻辑也一致。4.2 转换过程中的性能考量虽然组件内部做了优化但如果数据量特别大比如上万条转换本身也会消耗时间。我实测过5000条扁平数据转换成树形大概需要50-80毫秒10000条大概150-200毫秒。这个时间在可接受范围内但如果你的数据量更大建议在后端做分页或者懒加载。另外转换后的数据会缓存在组件内部如果原始数据变了需要重新设置tableData才能触发重新转换。直接修改数组里的某个元素组件可能不会重新转换这点要注意。4.3 两种方式的数据互转有时候后端返回的是嵌套结构但你想用方式二的配置或者反过来。其实可以自己写一个转换函数。扁平转嵌套比较简单function flatToTree(flatData, rowField id, parentField parentId) { const map {} const roots [] flatData.forEach(item { map[item[rowField]] { ...item, children: [] } }) flatData.forEach(item { const node map[item[rowField]] if (item[parentField] null || item[parentField] undefined) { roots.push(node) } else { const parent map[item[parentField]] if (parent) { parent.children.push(node) } } }) return roots }嵌套转扁平也不难递归遍历就行。不过既然vxe-table已经支持了两种方式大多数情况下没必要自己转除非你有特殊需求。5. 分页场景下的树形表格处理5.1 分页与树形的天然矛盾分页和树形表格放在一起本身就是一个矛盾的需求。分页是把数据切分成多页每页独立展示树形表格是要求父子节点在同一页里展示否则展开后看不到子节点。所以处理分页树形表格核心问题就是如何保证父子节点在同一页。常见的处理策略有三种只分页根节点每页展示固定数量的根节点每个根节点下的所有子节点都完整展示。这种方式最简单但每页的数据量不固定可能某一页特别长。按层级分页每一级单独分页展开时加载下一级。这种方式交互复杂但数据量可控。前端分页后端一次性返回所有数据前端做分页。这种方式只适合数据量小的场景。5.2 只分页根节点的实现这是最常用的方式。后端接口接收分页参数但只对根节点进行分页每个根节点返回完整的子树。前端配置和普通树形表格一样只是数据源变成了分页后的数据。const fetchData async (page, pageSize) { const res await api.getOrgTree({ page, pageSize }) tableData.value res.data.list total.value res.data.total }这种方式的关键在于后端接口的设计。后端需要先查询根节点的总数然后分页查询根节点再对每个根节点递归查询子节点。如果子节点数据量大接口响应可能会比较慢。注意这种方式下分页组件显示的总数是根节点的总数不是所有节点的总数。如果用户期望看到所有节点的数量需要在界面上说明清楚。5.3 前端分页的适用场景如果数据量不大比如几百条可以后端一次性返回所有数据前端用slice做分页。但要注意前端分页时树形结构会被破坏因为slice可能把父子节点切到不同的页。所以前端分页必须配合“只分页根节点”的策略也就是先在前端把数据转成树形然后对根节点数组做slice。const pagedData computed(() { const start (currentPage.value - 1) * pageSize.value const end start pageSize.value return treeData.value.slice(start, end) })这种方式只适合数据量小、层级浅的场景。数据量大了之后前端转换和渲染的性能都会成为瓶颈。5.4 分页切换时的展开状态保持分页切换时树形表格的展开状态默认会重置。如果用户希望切换回来时保持之前的展开状态需要自己记录。可以在toggle-tree-expand事件里记录展开的行ID切换分页后再恢复const expandedIds ref(new Set()) const handleToggleExpand ({ row, expanded }) { if (expanded) { expandedIds.value.add(row.id) } else { expandedIds.value.delete(row.id) } } // 数据加载完成后恢复展开状态 const restoreExpand () { tableData.value.forEach(row { if (expandedIds.value.has(row.id)) { tableRef.value.setTreeExpand(row, true) } }) }这个功能不是必须的但用户体验会好很多。尤其是当用户展开了一层节点去查看详情切换分页再回来发现全折叠了会很烦躁。6. 常见问题与排查技巧实录6.1 树形图标不显示这是最常见的问题。原因通常是treeNode: true没有加在正确的列上。检查一下你的列配置确保只有一列加了treeNode: true而且这一列是展示名称的列。如果加了还是不行检查tree-config里的children字段名是否和后端返回的一致。还有一种情况是数据里children字段是null而不是空数组。vxe-table对null的处理可能和空数组不一样建议后端返回空数组而不是null。6.2 展开后子节点不显示如果点击展开图标后没有子节点显示先检查数据里有没有children字段以及children是不是数组。如果数据是异步加载的检查loadMethod的返回值是不是数组。另外如果用了transform: true检查rowField和parentField配置是否正确特别是parentField的值是否和根节点的标识匹配。6.3 分页后树形结构错乱这个问题通常是因为分页把父子节点切到了不同的页。解决方法是采用“只分页根节点”的策略确保每个根节点下的所有子节点都在同一页。如果后端接口不支持可以考虑前端分页或者改用懒加载模式。6.4 性能问题排查树形表格的性能问题通常表现为展开卡顿、滚动卡顿。可以从以下几个方面排查数据量是否过大超过5000条建议用懒加载是否有不必要的响应式数据比如把整个表格数据放在reactive里列是否过多超过20列建议用虚拟滚动是否开启了expandAll数据量大时建议关闭vxe-table支持虚拟滚动配置scroll-y的gt参数即可开启。虚拟滚动可以大幅提升大数据量下的渲染性能但树形表格的虚拟滚动支持有限需要实测。6.5 常见问题速查表问题现象可能原因解决方法树形图标不显示未配置treeNode在名称列加treeNode: true子节点不显示children字段名不对检查tree-config的children配置展开无反应数据不是数组确保children是数组分页后结构错乱父子节点被切分只分页根节点展开卡顿数据量过大用懒加载或虚拟滚动异步加载失败loadMethod返回值不对确保返回数组切换分页后折叠展开状态未保持记录展开ID并恢复6.6 几个实操心得第一个心得如果后端返回的扁平数据里根节点的parentId是空字符串而不是nulltransform可能识别不了。这时候要么让后端改成null要么在前端做一次预处理把空字符串转成null。第二个心得树形表格的列宽最好固定不要用自适应。因为展开图标会占用空间自适应列宽在展开折叠时会导致列宽跳动体验很差。第三个心得如果表格需要支持排序树形表格的排序默认只对当前层级生效不会跨层级排序。如果需要全局排序需要自己实现。第四个心得在Vue 3里用vxe-table建议用ref而不是reactive来定义表格数据因为reactive的深层响应式在数据量大时性能损耗明显。第五个心得如果树形表格需要导出Excelvxe-table提供了导出功能但默认导出的是当前展开的数据。如果需要导出全部数据需要先展开所有节点再导出。7. 两种方式的最终选型建议聊了这么多最后说一下我的选型建议。如果你正在做的是一个新项目后端接口还没定我建议用扁平数据父子ID关联的方式。原因有三第一扁平结构在数据库里存储和查询都更方便后端开发成本低第二前端转换的性能可以接受而且组件内部做了优化第三扁平结构在分页和懒加载场景下更灵活。如果你接手的是一个老项目后端已经返回了嵌套结构那就直接用嵌套children结构的方式没必要为了统一而让后端改接口。改接口的成本和风险往往比前端适配要高。如果数据量特别大比如超过一万条不管用哪种方式都建议用懒加载。一次性加载所有数据再渲染用户体验会很差。懒加载虽然交互上多了一次请求但首屏加载速度快很多。分页场景下如果产品经理要求必须分页那就用“只分页根节点”的策略并且和后端约定好接口格式。如果产品经理可以接受不分页那就用懒加载虚拟滚动体验其实比分页更好。这个内容后续还可以这样扩展结合权限控制不同角色的用户看到不同的树形节点结合拖拽排序实现树形节点的动态调整结合搜索功能实现树形表格的节点过滤和高亮。这些都是在实际项目中可能会遇到的需求有机会再单独展开聊。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号