树形菜单是前端开发中常见的交互组件,用于展示具有层级关系的数据(如文件目录、分类列表、组织架构等)。以下从核心概念、实现方式、常见功能及优化方向等方面进行总结。
一、核心概念
- 层级结构:数据以父子嵌套形式存在,如
{ id: 1, children: [{ id: 2 }] }
。 - 节点:树形结构的基本单元,包含自身信息及子节点(若有)。
- 展开 / 折叠:子节点的显示与隐藏切换,是树形菜单的核心交互。
- 递归渲染:因数据层级不固定,通常通过递归函数生成 DOM 结构。
二、数据格式设计
常见的树形数据格式(以 JSON 为例):
javascript
const treeData = [
{
id: 1,
label: "父节点1",
// 可选:是否默认展开
expanded: false,
// 可选:是否禁用节点
disabled: false,
// 子节点(数组,无则为叶子节点)
children: [
{ id: 11, label: "子节点1-1", children: [] },
{ id: 12, label: "子节点1-2" }
]
},
{ id: 2, label: "父节点2" }
];
三、实现方式
1. 原生 JavaScript + DOM 操作
核心步骤:
- 定义递归函数,根据数据生成节点 DOM。
- 为父节点添加点击事件,控制子节点显示 / 隐藏。
- 处理特殊状态(如禁用、默认展开)。
示例代码片段:
javascript
function renderTree(data, container) {
const ul = document.createElement("ul");
data.forEach(node => {
const li = document.createElement("li");
li.innerHTML = `
<span class="node-label ${node.disabled ? 'disabled' : ''}">
${node.children?.length ? (node.expanded ? '▼' : '►') : '•'} ${node.label}
</span>
`;
// 处理展开/折叠
if (node.children?.length && !node.disabled) {
li.querySelector(".node-label").addEventListener("click", () => {
node.expanded = !node.expanded;
li.querySelector("ul")?.classList.toggle("hidden");
li.querySelector(".node-label").firstChild.textContent = node.expanded ? '▼' : '►';
});
// 递归渲染子节点
const ch