Bootstrap Table 树形表格插件详解:treegrid 扩展实战
1. 痛点解析:传统表格的层级数据展示困境
你是否还在为以下问题困扰?
- 层级数据(如部门结构、分类目录)在普通表格中展示混乱
- 大量展开/折叠按钮占据表格空间,影响数据密度
- 树形结构与表格排序、分页功能冲突
- 自定义树形样式需要编写大量额外代码
本文将系统讲解 Bootstrap Table 的 treegrid 扩展,通过 5 个实战案例和 3 种高级技巧,帮助你在 30 分钟内掌握层级数据的优雅展示方案。
2. 核心概念与工作原理
2.1 基本定义
树形表格(TreeGrid)是一种能够展示具有层级关系数据的表格组件,它通过缩进和连接线直观呈现父子关系,同时保留普通表格的排序、筛选和分页功能。
2.2 实现原理
treegrid 扩展通过以下机制实现树形展示:
- 解析数据中的父子关系字段(idField 和 parentIdField)
- 递归构建 DOM 结构,通过 CSS 实现层级缩进
- 集成 jquery-treegrid 实现连接线渲染
- 重写表格行初始化方法,保持与 Bootstrap Table 核心功能兼容
3. 快速开始:5 分钟实现基础树形表格
3.1 引入必要资源
<!-- 引入依赖 -->
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/jquery-treegrid/0.3.0/css/jquery.treegrid.min.css">
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery-treegrid/0.3.0/js/jquery.treegrid.min.js"></script>
<!-- 引入Bootstrap Table核心文件 -->
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/bootstrap-table/1.22.1/bootstrap-table.min.css">
<script src="https://cdn.bootcdn.net/ajax/libs/bootstrap-table/1.22.1/bootstrap-table.min.js"></script>
<!-- 引入treegrid扩展 -->
<script src="https://cdn.bootcdn.net/ajax/libs/bootstrap-table/1.22.1/extensions/treegrid/bootstrap-table-treegrid.min.js"></script>
3.2 HTML结构
<table id="treeTable" class="table table-striped table-bordered"></table>
3.3 JavaScript初始化
$('#treeTable').bootstrapTable({
url: 'data.json',
treeEnable: true,
treeShowField: 'name',
idField: 'id',
parentIdField: 'pid',
rootParentId: 0,
columns: [
{ field: 'name', title: '名称' },
{ field: 'code', title: '编码' },
{ field: 'level', title: '层级' },
{ field: 'status', title: '状态' }
]
});
3.4 示例数据格式
[
{ "id": 1, "pid": 0, "name": "总公司", "code": "COMPANY", "level": 1, "status": "正常" },
{ "id": 2, "pid": 1, "name": "技术部", "code": "TECH", "level": 2, "status": "正常" },
{ "id": 3, "pid": 1, "name": "市场部", "code": "MARKET", "level": 2, "status": "正常" },
{ "id": 4, "pid": 2, "name": "前端团队", "code": "FRONTEND", "level": 3, "status": "正常" },
{ "id": 5, "pid": 2, "name": "后端团队", "code": "BACKEND", "level": 3, "status": "正常" },
{ "id": 6, "pid": 4, "name": "UI组", "code": "UI", "level": 4, "status": "正常" },
{ "id": 7, "pid": 4, "name": "JS组", "code": "JS", "level": 4, "status": "维护中" }
]
3.5 效果展示
┌──────────┬──────────┬──────┬────────┐
│ 名称 │ 编码 │ 层级 │ 状态 │
├──────────┼──────────┼──────┼────────┤
│ 总公司 │ COMPANY │ 1 │ 正常 │
│ ├技术部 │ TECH │ 2 │ 正常 │
│ │ ├前端团队│ FRONTEND │ 3 │ 正常 │
│ │ │ ├UI组 │ UI │ 4 │ 正常 │
│ │ │ └JS组 │ JS │ 4 │ 维护中 │
│ │ └后端团队│ BACKEND │ 3 │ 正常 │
│ └市场部 │ MARKET │ 2 │ 正常 │
└──────────┴──────────┴──────┴────────┘
4. 核心配置项详解
| 配置项 | 数据类型 | 默认值 | 描述 | 重要性 |
|---|---|---|---|---|
| treeEnable | Boolean | false | 是否启用树形表格功能 | ★★★★★ |
| treeShowField | String | null | 指定作为树形展示的字段名,设置后自动启用树形功能 | ★★★★★ |
| idField | String | 'id' | 数据唯一标识字段名 | ★★★★★ |
| parentIdField | String | 'pid' | 父节点标识字段名 | ★★★★★ |
| rootParentId | Any | null | 根节点的父ID值 | ★★★★☆ |
4.1 treeEnable 与 treeShowField 的关系
最佳实践:推荐使用 treeShowField 配置,它会自动启用树形功能并指定展开/折叠图标位置。
5. 实战案例
5.1 案例一:部门人员层级表
需求:展示公司部门和人员的层级关系,支持按姓名搜索和职位筛选。
$('#deptTable').bootstrapTable({
data: departmentData,
treeShowField: 'name',
idField: 'id',
parentIdField: 'parentId',
rootParentId: null,
search: true,
columns: [
{
field: 'name',
title: '名称',
formatter: function(value, row) {
// 自定义图标区分部门和人员
const icon = row.type === 'dept' ? 'folder' : 'user';
return `<i class="glyphicon glyphicon-${icon}"></i> ${value}`;
}
},
{ field: 'title', title: '职位' },
{ field: 'email', title: '邮箱' },
{ field: 'phone', title: '电话' },
{
field: 'action',
title: '操作',
formatter: function() {
return '<button class="btn btn-xs btn-primary">编辑</button>';
}
}
]
});
5.2 案例二:文件目录浏览器
需求:模拟文件系统目录结构,支持双击展开/折叠,右键菜单操作。
$('#fileExplorer').bootstrapTable({
data: fileData,
treeShowField: 'name',
idField: 'id',
parentIdField: 'pid',
rootParentId: 0,
clickToSelect: true,
onDblClickCell: function(field, value, row, $element) {
// 双击切换展开/折叠状态
if (field === 'name') {
const $tr = $element.closest('tr');
if ($tr.hasClass('treegrid-collapsed')) {
$tr.treegrid('expand');
} else if ($tr.hasClass('treegrid-expanded')) {
$tr.treegrid('collapse');
}
}
},
columns: [
{
field: 'name',
title: '文件名',
formatter: function(value, row) {
const icon = row.isDir ? 'folder-open' : 'file';
return `<i class="glyphicon glyphicon-${icon}"></i> ${value}`;
}
},
{ field: 'size', title: '大小', formatter: v => v || '-' },
{ field: 'modifyTime', title: '修改时间' }
]
});
// 初始化右键菜单
$('#fileExplorer').on('contextmenu', 'tr', function(e) {
e.preventDefault();
// 显示自定义右键菜单
$('#fileContextMenu').css({
top: e.pageY,
left: e.pageX
}).show();
});
5.3 案例三:树形结构与分页混合使用
需求:大数据量层级结构,需要分页加载子节点数据。
$('#bigDataTree').bootstrapTable({
url: '/api/tree-data',
treeShowField: 'name',
idField: 'id',
parentIdField: 'pid',
rootParentId: 0,
sidePagination: 'server',
pagination: true,
pageSize: 10,
onLoadSuccess: function(data) {
// 初始化treegrid
$('#bigDataTree').treegrid({
initialState: 'collapsed',
expanderExpandedClass: 'glyphicon glyphicon-chevron-down',
expanderCollapsedClass: 'glyphicon glyphicon-chevron-right'
});
},
columns: [
{ field: 'name', title: '名称' },
{ field: 'code', title: '编码' },
{ field: 'desc', title: '描述' }
]
});
后端API设计:
GET /api/tree-data?page=1&rows=10&parentId=0 // 获取根节点
GET /api/tree-data?page=1&rows=10&parentId=1 // 获取ID=1的子节点
6. 高级技巧与定制化
6.1 自定义展开/折叠图标
/* 自定义展开/折叠图标样式 */
.treegrid-expander {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="5 9 12 16 19 9"></polyline></svg>');
width: 16px;
height: 16px;
}
.treegrid-collapsed .treegrid-expander {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 5 12 8 15 5"></polyline><polyline points="9 19 12 16 15 19"></polyline></svg>');
}
6.2 动态加载子节点
// 实现点击展开时才加载子节点数据
$('#dynamicTree').bootstrapTable({
data: rootData, // 仅加载根节点数据
treeShowField: 'name',
idField: 'id',
parentIdField: 'pid',
onExpandRow: function(index, row, $detail) {
// 检查是否已加载过子节点
if (!row.childrenLoaded) {
$.get(`/api/children/${row.id}`, function(data) {
// 添加子节点数据
$('#dynamicTree').bootstrapTable('append', data);
// 标记为已加载
row.childrenLoaded = true;
});
}
},
columns: [/* 列定义 */]
});
6.3 树形表格与拖拽排序结合
// 集成拖拽功能
$('#draggableTree').bootstrapTable({
treeShowField: 'name',
idField: 'id',
parentIdField: 'pid',
// 其他配置...
})
// 初始化拖拽
$('#draggableTree').find('tbody').sortable({
items: 'tr:not(.has-children)',
cursor: 'move',
update: function(event, ui) {
const movedRow = ui.item;
const newParent = movedRow.prev();
const newParentId = newParent.data('uniqueid') || null;
// 发送更新请求
$.post('/api/update-position', {
id: movedRow.data('uniqueid'),
newParentId: newParentId,
newOrder: movedRow.index()
});
}
});
7. 常见问题与解决方案
7.1 问题:树形表格与分页功能冲突
原因:默认分页会将数据分割成多页,破坏树形结构的完整性。
解决方案:
- 对于少量数据:禁用分页 (
pagination: false) - 对于大量数据:实现服务端树形分页(见5.3案例)
- 使用虚拟滚动 (
virtualScroll: true) 替代传统分页
7.2 问题:搜索功能无法匹配子节点
解决方案:重写搜索逻辑,实现递归搜索
$.fn.bootstrapTable.locales['zh-CN'].formatSearch = function() {
return '搜索所有层级:';
};
// 重写搜索方法
$.fn.bootstrapTable.Constructor.prototype.onSearch = function(event) {
event.preventDefault();
const searchText = this.$searchInput.val().toLowerCase();
if (this.options.treeEnable) {
// 树形表格搜索逻辑
this.data = this.options.data.filter(row => {
// 递归检查节点及其所有后代
const hasMatch = (node) => {
// 检查当前节点
if (JSON.stringify(node).toLowerCase().includes(searchText)) {
return true;
}
// 检查子节点
const children = this.options.data.filter(child =>
child[this.options.parentIdField] === node[this.options.idField]
);
return children.some(hasMatch);
};
// 只返回根节点或匹配节点
return hasMatch(row) &&
(row[this.options.parentIdField] === this.options.rootParentId);
});
this.initBody();
} else {
// 调用默认搜索方法
this._super(event);
}
};
7.3 问题:连接线样式不显示或错位
解决方案:
- 确保正确引入 jquery-treegrid 的 CSS 文件
- 检查表格是否设置了固定列(fixedColumns),两者可能冲突
- 自定义连接线样式适配你的表格布局:
/* 修复连接线显示问题 */
.treegrid-indent {
width: 24px;
display: inline-block;
}
/* 调整连接线位置 */
.treegrid-expander {
margin-left: -16px;
margin-right: 8px;
}
8. 性能优化策略
对于超过1000行的大型树形表格,建议采用以下优化措施:
- 数据分片加载:只加载当前展开节点的子节点(见6.2案例)
- 虚拟滚动:启用
virtualScroll: true,只渲染可视区域内的行 - 延迟渲染:使用
deferRender: true延迟DOM创建 - CSS优化:避免使用复杂选择器和阴影效果
- 事件委托:将事件绑定到表格而非单个行
// 高性能配置示例
{
treeEnable: true,
treeShowField: 'name',
virtualScroll: true,
virtualScrollItemHeight: 38,
deferRender: true,
pageSize: 200, // 虚拟滚动每页大小
cache: true, // 启用缓存
// 其他配置...
}
9. 总结与展望
Bootstrap Table 的 treegrid 扩展为层级数据展示提供了简洁而强大的解决方案,其核心优势包括:
- 与 Bootstrap Table 无缝集成,保留所有原有功能
- 简洁的配置 API,降低使用门槛
- 灵活的扩展性,支持自定义图标、样式和行为
- 轻量级实现,性能表现优异
未来发展方向:
- 原生支持虚拟滚动树形结构
- 内置拖拽排序功能
- 支持更复杂的树形数据结构(如多父节点)
- 增强无障碍访问支持
掌握 treegrid 扩展不仅能提升数据展示的美观度,更能显著改善用户对层级数据的理解和操作效率。建议结合实际项目需求,灵活运用本文介绍的配置项和高级技巧,打造专业级的树形表格体验。
10. 学习资源与社区
- 官方文档:Bootstrap Table 官方扩展文档
- GitHub仓库:https://gitcode.com/gh_mirrors/bo/bootstrap-table
- 示例集合:examples.bootstrap-table.com/#extensions/treegrid.html
- 社区支持:StackOverflow 上的
bootstrap-table标签
实践作业:尝试实现一个"多级评论系统",要求支持无限层级嵌套、评论点赞和回复功能,巩固本文所学知识。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



