php实现树形菜单
PHP实现树形菜单的方法
数据库设计
创建一个表存储菜单项,通常包含字段如id、name、parent_id(父级ID,根节点为0或NULL)和order(排序字段)。示例SQL结构:
CREATE TABLE menu_items (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
parent_id INT DEFAULT NULL,
order INT DEFAULT 0,
FOREIGN KEY (parent_id) REFERENCES menu_items(id) ON DELETE CASCADE
);
递归查询数据
从数据库获取所有菜单项,使用递归函数构建树形结构:
function buildTree(array $items, $parentId = null) {
$branch = [];
foreach ($items as $item) {
if ($item['parent_id'] == $parentId) {
$children = buildTree($items, $item['id']);
if ($children) {
$item['children'] = $children;
}
$branch[] = $item;
}
}
return $branch;
}
// 使用示例
$items = $pdo->query("SELECT * FROM menu_items ORDER BY `order`")->fetchAll(PDO::FETCH_ASSOC);
$tree = buildTree($items);
渲染HTML菜单
通过递归函数生成嵌套的HTML列表:
function renderMenu(array $tree) {
echo '<ul>';
foreach ($tree as $node) {
echo '<li>';
echo htmlspecialchars($node['name']);
if (!empty($node['children'])) {
renderMenu($node['children']);
}
echo '</li>';
}
echo '</ul>';
}
// 调用渲染
renderMenu($tree);
使用闭包优化
对于大型数据集,可用闭包避免多次循环:
function buildTreeWithClosure(array $items) {
$grouped = [];
foreach ($items as $item) {
$grouped[$item['parent_id']][] = $item;
}
$build = function($parentId) use (&$build, $grouped) {
return array_map(function($item) use ($build) {
if (isset($grouped[$item['id']])) {
$item['children'] = $build($item['id']);
}
return $item;
}, $grouped[$parentId] ?? []);
};
return $build(0);
}
前端交互增强
结合jQuery实现折叠效果:
<script>
$(document).ready(function() {
$('.tree-menu li').has('ul').prepend('<span class="toggle">+</span>');
$('.tree-menu .toggle').click(function() {
$(this).text($(this).text() === '+' ? '-' : '+')
.siblings('ul').toggle();
});
});
</script>
性能优化建议
- 对静态菜单使用缓存(如Redis或文件缓存)
- 数据库查询时添加
INDEX到parent_id字段 - 超深层级树可改用嵌套集模型(Nested Set)替代邻接表
完整示例代码
// 数据库连接
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
// 获取数据并构建树
$items = $pdo->query("SELECT * FROM menu_items ORDER BY `order`")->fetchAll(PDO::FETCH_ASSOC);
$menuTree = buildTreeWithClosure($items);
// 渲染菜单
echo '<div class="tree-menu">';
renderMenu($menuTree);
echo '</div>';






