Laravel 8.x 实现无限级分类树形菜单需后端嵌套数据+前端递归渲染:模型设 nullable parent_id 并定义 children 关系,控制器用 with 预加载;Blade 中通过 @include 递归渲染 _node 模板,配合 CSS 缩进与可选 JS 交互。

在 Laravel 8.x 中实现无限级分类的前端树形菜单,核心是「后端提供结构化嵌套数据 + 前端递归渲染」。不依赖第三方包也能高效完成,关键是数据组织方式和 Blade 模板的递归写法要匹配。
后端:用 Eloquent 预加载构建嵌套树
确保分类模型中定义好父子关系:
- 迁移字段必须允许 null:`$table->foreignId('parent_id')->nullable()->constrained()->nullOnDelete();`(不能设 default(0) 或 unsigned 且非空)
-
模型中声明关系:
public function children() { return $this->hasMany(Category::class, 'parent_id'); } <p>// 用于一次性加载整棵树(含所有后代) public function descendantsAndSelf() { return $this->children()->with('descendantsAndSelf'); }</p> -
控制器中获取根节点并预加载全树:
$categories = Category::whereNull('parent_id') ->with(['children' => fn($q) => $q->with('children')]) ->get();注意:Laravel 8.x 的 `with()` 支持闭包嵌套,最多展开两层已够多数场景;若需真正无限深度,可改用递归集合处理(见下文补充)。
前端:Blade 中用 @include 实现递归模板
在 resources/views/categories/index.blade.php 中写主入口:
再新建 resources/views/categories/_node.blade.php(关键递归文件):
-
@foreach($node->children as $child)
@include('categories._node', ['node' => $child])
@endforeach
这样就完成了无 JS、零依赖的纯服务端递归渲染。样式可通过 CSS 控制缩进(如 padding-left: calc({{ $depth ?? 0 }} * 24px),需在 include 时传入 depth 参数)。
补充:需要动态交互?加简单 JS 展开/收起
如果希望点击箭头控制子菜单显隐,只需给每个 加初始 `style="display:none"`,再用轻量 JS 绑定 toggle:
- 为父节点 label 添加 data-id 和 toggle 按钮
- JS 监听点击,切换对应 ul 的 display 状态
- 无需 Vue/React,10 行原生 JS 就够用
避坑提醒
常见翻车点集中在后端数据构造环节:
- 用
with('children')却没限制层级 → 触发 N+1 查询或内存溢出 - 数据库里 parent_id 类型为 unsignedBigInteger 但值为 0 → 根节点查不到(应为 null)
- Blade 递归未设终止条件(如漏掉
@if($node->children->count()))→ 报错或空数组报错 - 直接在模板里写 PHP 递归函数 → 不推荐,破坏视图职责,也难调试
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











