Laravel中实现无限级分类按层级递归排序及分页的方法
Laravel 无限层级分类递归展示与分页实现方案
前置准备:表结构设计
首先确保你的分类表包含基础层级字段,推荐字段如下:
id:主键name:分类名称parent_id:父分类ID,顶级分类默认值为0或NULLsort:同层级排序字段(可选,用于自定义同层级分类的展示顺序)
小数据量实现方案(分类数<100)
如果分类总量不大,可以先递归把所有分类整理为带层级的扁平化集合,再手动生成分页器。
1. 模型添加递归拉平方法
在app/Models/Category.php中添加获取扁平化分类的方法:
public static function getFlattenedTree(int $parentId = 0, int $depth = 0): \Illuminate\Support\Collection { $result = collect(); // 按排序规则查询当前层级分类 $categories = self::where('parent_id', $parentId) ->orderBy('sort', 'asc') ->orderBy('id', 'asc') ->get(); foreach ($categories as $category) { // 给当前分类附加层级深度字段,用于前端缩进展示 $category->depth = $depth; $result->push($category); // 递归合并子分类 $result = $result->merge(self::getFlattenedTree($category->id, $depth + 1)); } return $result; }
2. 控制器手动生成分页器
Laravel默认分页只支持查询构造器,因此需要手动对集合做分页处理:
use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\Paginator; public function index(Request $request) { // 获取全部整理好的扁平化分类 $allCategories = Category::getFlattenedTree(); $perPage = 10; $currentPage = Paginator::resolveCurrentPage('page'); // 切割当前页需要的10条数据 $pageItems = $allCategories->slice(($currentPage - 1) * $perPage, $perPage)->values(); // 生成长度感知分页器 $categories = new LengthAwarePaginator( $pageItems, $allCategories->count(), $perPage, $currentPage, ['path' => Paginator::resolveCurrentPath()] ); return view('categories.index', compact('categories')); }
3. 前端渲染加缩进
在Blade模板中根据depth字段控制缩进,实现层级展示效果:
<ul> @foreach($categories as $category) <li style="padding-left: {{ $category->depth * 20 }}px"> {{ $category->name }} </li> @endforeach </ul> <!-- 输出分页链接 --> {{ $categories->links() }}
大数据量优化方案(分类数≥100,推荐)
如果分类总量很大,递归拉全量数据会有性能问题,推荐使用**嵌套集合(Nested Set)**模型实现:
- 安装
kalnoy/nestedset扩展,按照文档配置Category模型,扩展会自动维护lft、rgt、depth三个字段,用于标识分类的层级和顺序 - 查询时直接按
lft字段升序排序,即可得到父分类在前、子分类紧跟的递归顺序,直接调用Laravel自带的分页方法即可:
$categories = Category::orderBy('lft', 'asc')->paginate(10);
前端渲染逻辑和小数据量方案完全一致,无需额外处理。
注意事项
- 若需要自定义同层级分类的排序规则,可以在排序条件中额外增加sort字段,比如
orderBy('sort', 'asc')->orderBy('lft', 'asc') - 使用嵌套集合模型时,新增、修改、移动、删除分类都要使用扩展包提供的方法,不要直接操作
lft、rgt字段,扩展会自动维护字段值。
内容的提问来源于stack exchange,提问作者G60
相关产品推荐
相关产品推荐

