HTML表格如何实现树形结构显示?有哪些实现方式?
在Web开发中,树形结构的数据展示是非常常见的需求,例如组织架构图、文件目录、多级分类等。虽然HTML原生的<ul>和<li>列表更适合展示树形结构,但在需要展示多列属性数据时,表格<table>依然是首选。那么,如何在HTML表格中实现树形结构的显示呢?本文将详细介绍几种常见的实现方式。
一、纯HTML/CSS实现(缩进模拟法)
最简单直接的方式是通过CSS的padding-left或margin-left属性来模拟层级缩进,同时配合图标来表示展开/折叠状态。这种方式适用于纯静态展示,或者不需要复杂交互的简单树形结构。
实现原理:给不同层级的<tr>添加不同的类名,通过类名控制左侧的缩进量。
<style>
.tree-table { width: 100%; border-collapse: collapse; }
.tree-table td { border: 1px solid #ccc; padding: 8px; }
.level-1 .node-name { padding-left: 20px; }
.level-2 .node-name { padding-left: 40px; }
.level-3 .node-name { padding-left: 60px; }
</style>
<table class="tree-table">
<tr class="level-1">
<td class="node-name">[+] 父节点 1</td>
<td>数据信息</td>
</tr>
<tr class="level-2">
<td class="node-name">├─ 子节点 1-1</td>
<td>数据信息</td>
</tr>
<tr class="level-3">
<td class="node-name">│ └─ 孙节点 1-1-1</td>
<td>数据信息</td>
</tr>
<tr class="level-1">
<td class="node-name">? 父节点 2</td>
<td>数据信息</td>
</tr>
</table>优点: 实现简单,无需依赖JS,兼容性极好。
缺点: 无法动态展开/折叠,如果层级过深需要写大量的CSS类名。
二、原生JavaScript实现(DOM操作法)
如果需要点击父节点展开或折叠子节点,就需要引入JavaScript。我们可以通过HTML5的data-*自定义属性来标记行与行之间的父子关系,然后通过JS控制子行的显示与隐藏。
实现原理:给每一行设置data-id和data-pid(父级ID),点击某行时,遍历表格所有行,找到data-pid等于当前行data-id的行,切换它们的显示状态。
<table id="treeTable" border="1">
<tr data-id="1" data-pid="0">
<td><span class="toggle">[-]</span> 父节点 1</td>
<td>信息</td>
</tr>
<tr data-id="2" data-pid="1">
<td style="padding-left:20px;">子节点 1-1</td>
<td>信息</td>
</tr>
<tr data-id="3" data-pid="1">
<td style="padding-left:20px;">子节点 1-2</td>
<td>信息</td>
</tr>
<tr data-id="4" data-pid="0">
<td><span class="toggle">[-]</span> 父节点 2</td>
<td>信息</td>
</tr>
</table>
<script>
document.getElementById('treeTable').addEventListener('click', function(e) {
if (e.target.classList.contains('toggle')) {
var parentRow = e.target.closest('tr');
var parentId = parentRow.getAttribute('data-id');
var rows = document.querySelectorAll('#treeTable tr');
// 切换图标状态
e.target.textContent = e.target.textContent === '[-]' ? '[+]' : '[-]';
// 递归切换子节点显示状态
rows.forEach(function(row) {
if (row.getAttribute('data-pid') === parentId) {
var isHidden = row.style.display === 'none';
row.style.display = isHidden ? '' : 'none';
// 如果隐藏父节点,其所有子孙节点也要隐藏
if (!isHidden) {
var childId = row.getAttribute('data-id');
rows.forEach(function(childRow) {
if (childRow.getAttribute('data-pid') === childId) {
childRow.style.display = 'none';
}
});
}
}
});
}
});
</script>优点: 实现了交互功能,无第三方依赖。
缺点: 需要手动处理缩进逻辑,多层嵌套时的递归显隐控制较为复杂,性能在数据量极大时可能受影响。
三、使用现代前端UI框架组件
在实际的企业级开发中,最推荐的方式是使用成熟的UI组件库(如Element UI、Ant Design等)。这些库提供了现成的树形表格组件,内置了展开/折叠、复选框联动、异步加载等高级功能。
以 Vue + Element UI 为例,只需在 <el-table> 中配置 row-key 和 :tree-props 即可轻松实现:
<template>
<el-table
:data="tableData"
style="width: 100%"
row-key="id"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
>
<el-table-column prop="name" label="名称" width="180"></el-table-column>
<el-table-column prop="desc" label="描述"></el-table-column>
</el-table>
</template>
<script>
export default {
data() {
return {
tableData: [{
id: 1,
name: '父节点 1',
desc: '这是父节点',
children: [{
id: 4,
name: '子节点 1-1',
desc: '这是子节点'
}]
}, {
id: 2,
name: '父节点 2',
desc: '这是父节点',
children: [{
id: 5,
name: '子节点 2-1',
desc: '这是子节点'
}]
}]
}
}
}
</script>优点: 开箱即用,功能强大,样式美观,维护成本低。
缺点: 需要引入特定的前端框架和UI库,增加了项目的体积。
四、使用jQuery插件(传统项目适用)
对于一些老旧的jQuery项目,可以使用 jquery-treetable 等插件。这类插件通过将普通的<table>标签初始化,自动生成树形结构和交互逻辑。
你可以访问 www.ipipp.com 查看相关的Demo演示。
$("#tree-table").treetable({
expandable: true,
indent: 20, // 每层缩进像素
initialState: "expanded" // 初始状态展开
});优点: 兼容老项目,配置简单。
缺点: 依赖jQuery,不符合现代前端开发趋势。
总结
HTML表格实现树形结构有多种选择,具体采用哪种取决于项目需求:
如果只是静态展示,推荐纯CSS缩进法;
如果是轻量级动态交互且不想引入框架,推荐原生JS的data-pid法;
如果是现代企业级应用,强烈建议使用UI框架的树形表格组件;
如果是维护老旧jQuery项目,则选择对应的jQuery插件。