Laravel 8.x 中 Blade 实现无限级分类的核心是自引用组件加递归调用,需定义 category-tree 组件、控制器预加载全量分类并按 parent_id 归组,再传入根节点集合渲染,避免 @include 和 N+1 问题。

在 Laravel 8.x 中,Blade 模板实现无限级分类的递归循环,核心是「自引用组件 + 递归调用」,不是靠 PHP 层手动拼数组,也不是依赖深度不确定的 with('children.children...')。这种方式结构清晰、渲染可控、无 N+1 风险。
定义可递归的 Blade 组件
在 resources/views/components/category-tree.blade.php 中创建一个组件:
$categories = $categories ?? collect();
$depth = $depth ?? 0;
?>
@foreach($categories as $category)
{{ str_repeat('─', $depth) }} {{ $category->name }}
@if($category->children->isNotEmpty())
@endif
@endforeach
注意:
• 组件名必须小写中划线格式(category-tree),对应文件名 category-tree.blade.php;
• 使用 :categories 和 :depth 传参,确保子调用能接收新数据;
• $category->children 需已在控制器中预加载(见下一条)。
控制器中预加载整棵树(关键!)
不要用 with('children') 简单嵌套——它只展开一层。要支持任意深度,必须用闭包预加载多层,或一次性查出全量再组织。
推荐做法(兼顾性能与兼容性):
- 在 Category 模型中定义关系:
public function children()
{
return $this->hasMany(Category::class, 'parent_id');
} - 控制器中一次性查出全部分类,并按 parent_id 归组:
$allCategories = Category::orderBy('sort')->get();
$tree = $allCategories->where('parent_id', null)->map(function ($root) use ($allCategories) {
return $root->merge(['children' => $this->buildChildren($root, $allCategories)]);
});
(其中buildChildren()是递归构建子集的私有方法) - 更轻量方案:直接传
$allCategories到视图,Blade 组件内用$allCategories->where('parent_id', $category->id)过滤子项(适合几百条以内)
在页面中使用组件
在你的主视图(如 categories/index.blade.php)中:
@props(['categories'])
并确保控制器传入的是根节点集合(例如 Category::whereNull('parent_id')->with('children') 的结果),或按上一步构造好的树形集合。
避免常见坑
• 不要在 Blade 里写 @foreach($categories as $c) @include('components.category-tree') —— @include 不支持动态传参绑定,且无法递归传参;
• 不要用 with('children.children.children') 硬写三层以上,既难维护又易漏层;
• 不在组件内做数据库查询(如 Category::where(...)),否则触发 N+1;
• 若层级过深(>10 层),建议前端用 JS 折叠控制,而非服务端全量渲染。











