递归函数实现树形菜单

  • 前言
  • 树形菜单的作用
  • 创建假数据或者请求接口数据
  • 定义递归函数,处理数据
  • 调用函数,渲染页面
  • 效果展示
  • 完整代码


前言

树形菜单是一种常见的网站导航方式,它通常由多个层级的菜单项组成,每个菜单项可以有子菜单项。在JavaScript中,我们可以使用递归函数来实现树形菜单。

树形菜单就是这样的东西,点击上一级,显示下一级,无限循环,一直逐层显示下一级。再次点击,关闭下一级。长的很像树,故名树形菜单。学会这个东西,是不是很酷?

js 树形结构 demo js 树形结构递归_开发语言


树形菜单的作用

树形菜单的主要作用是将信息层次化,将复杂的信息结构变得更加清晰和直观。它通常用于展示层级关系比较复杂的数据,如文件目录、网站导航、商品分类等。树形菜单的优点包括:

  1. 层次化展示:树形菜单可以将信息按照层级展示,使用户能够更加清晰地理解信息之间的关系。
  2. 简洁明了:树形菜单的结构简单明了,能够有效地减少信息的冗余,提高页面的整体美观度。
  3. 交互性强:树形菜单可以通过展开和收起节点的方式,使用户能够更加方便地获取所需信息。
  4. 可扩展性好:树形菜单可以根据需要随时添加新的节点,具有很好的扩展性。

创建假数据或者请求接口数据

首先,我们需要一个数据结构来表示树形菜单,通常可以使用嵌套的对象或数组来表示。每个菜单项包含以下属性:

下面是一个假数据:

const menu = [{
					label: '家人',
					children: [{
						label: '爹妈',
						children: [{
							label: '我',
							children: []
						}]
					}]
				},
				{
					label: '老师',
					children: [{
							label: '物理老师',
							children: [{
								label: '物理老师儿子',
								children: []
							}]
						},
						{
							label: '化学老师',
							children: [{
								label: '化学老师儿子',
								children: []
							}]
						}
					]
				},
				{
					label: '老板',
					children: [{
						label: '总经理',
						children: [{
								label: '领导1',
								children: [{
									label: '韩国分公司',
									children: []
								}]
							},
							{
								label: '领导2',
								children: [{
									label: '日本分公司',
									children: []
								}]
							}
						]
					}]
				}
			];

定义递归函数,处理数据

接下来,我们可以定义一个递归函数来遍历这个数据源,并且为每个菜单项添加点击事件。

下面是一个递归函数实现:

function createMenu(menuData) {
				const menuEl = document.createElement('ul');

				menuData.forEach(item => {
					const itemEl = document.createElement('li');
					const labelEl = document.createElement('span');
					labelEl.innerText = item.label;
					itemEl.appendChild(labelEl);

					if (item.children.length > 0) {
						labelEl.addEventListener('click', () => {
							if (itemEl.classList.contains('open')) {
								itemEl.classList.remove('open');
								itemEl.removeChild(itemEl.lastChild);
							} else {
								itemEl.classList.add('open');
								const submenuEl = createMenu(item.children);
								itemEl.appendChild(submenuEl);
							}
						});
					}
					menuEl.appendChild(itemEl);
				});
				return menuEl;
			}

调用函数,渲染页面

最后,我们可以调用这个函数来生成完整的树形菜单的HTML代码:

const menuEl = createMenu(menu);
			document.body.appendChild(menuEl);

这里假设树形菜单的容器元素的ID为menu。我们先取出这个元素,然后将生成的HTML代码插入到这个元素的innerHTML属性中,即可显示出树形菜单。


效果展示

js 树形结构 demo js 树形结构递归_开发语言_02


完整代码

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1">
		<title></title>
		<script src="./js/jquery-3.6.1.js"></script>
		<style></style>
	</head>
	<body>
		<script>
			const menu = [{
					label: '家人',
					children: [{
						label: '爹妈',
						children: [{
							label: '我',
							children: []
						}]
					}]
				},
				{
					label: '老师',
					children: [{
							label: '物理老师',
							children: [{
								label: '物理老师儿子',
								children: []
							}]
						},
						{
							label: '化学老师',
							children: [{
								label: '化学老师儿子',
								children: []
							}]
						}
					]
				},
				{
					label: '老板',
					children: [{
						label: '总经理',
						children: [{
								label: '领导1',
								children: [{
									label: '韩国分公司',
									children: []
								}]
							},
							{
								label: '领导2',
								children: [{
									label: '日本分公司',
									children: []
								}]
							}
						]
					}]
				}
			];

			function createMenu(menuData) {
				const menuEl = document.createElement('ul');

				menuData.forEach(item => {
					const itemEl = document.createElement('li');
					const labelEl = document.createElement('span');
					labelEl.innerText = item.label;
					itemEl.appendChild(labelEl);

					if (item.children.length > 0) {
						labelEl.addEventListener('click', () => {
							if (itemEl.classList.contains('open')) {
								itemEl.classList.remove('open');
								itemEl.removeChild(itemEl.lastChild);
							} else {
								itemEl.classList.add('open');
								const submenuEl = createMenu(item.children);
								itemEl.appendChild(submenuEl);
							}
						});
					}

					menuEl.appendChild(itemEl);
				});

				return menuEl;
			}

			const menuEl = createMenu(menu);
			document.body.appendChild(menuEl);
		</script>
	</body>
</html>