Laravel 5.5 自定义分页:将横版图片视为2页处理
解决Laravel分页中横版图片按2页计算的问题
要实现横版图片等价于2页的分页逻辑,Laravel默认的paginate()方法没法直接满足——它是按记录数分页的。我们需要自定义分页逻辑,基于图片的横竖版计算"虚拟页数权重",再筛选出当前页应该展示的图片,最后手动构建分页器实例。
核心思路与实现步骤
- 给每张图片分配权重:竖版(width ≤ height)权重1,横版(width > height)权重2
- 基于总权重计算虚拟总页数,而非按图片数量计算
- 匹配当前页对应的虚拟页数范围,筛选出该范围覆盖的图片
- 用Laravel的
LengthAwarePaginator构建自定义分页器,保持原有分页接口的兼容性
修改后的完整代码
/** * The attributes on which the comic list can be ordered * @var array */ public static $allowedSortingOptions = [ 'sort_order desc' => 'Sort Order (descending)', 'random' => 'Random' ]; /** * Lists images for the front end * * @param $query * @param array $options Display options * * @return \Illuminate\Pagination\LengthAwarePaginator */ public function scopeListFrontEnd($query, $options) { /* * Default options */ extract(array_merge([ 'page' => 1, 'perPage' => 1, 'sort' => 'sort_order', 'chapter' => null, 'language' => 'en' ], $options)); if($chapter) { $query->where('attachment_id', $chapter); } $query->where('language', $language); /* * Sorting */ if (!is_array($sort)) { $sort = [$sort]; } foreach ($sort as $_sort) { if (in_array($_sort, array_keys(self::$allowedSortingOptions))) { $parts = explode(' ', $_sort); if (count($parts) < 2) { array_push($parts, 'desc'); } list($sortField, $sortDirection) = $parts; if ($sortField == 'random') { $sortField = \DB::raw('RAND()'); } $query->orderBy($sortField, $sortDirection); } } // 1. 获取排序后的所有符合条件的图片 $allImages = $query->get(); // 2. 为每张图片计算权重 $weightedImages = $allImages->map(function($image) { $image->weight = $image->width > $image->height ? 2 : 1; return $image; }); // 3. 计算总虚拟页数(总权重 / 每页虚拟页数,向上取整) $totalWeight = $weightedImages->sum('weight'); $totalPages = (int)ceil($totalWeight / $perPage); // 4. 确定当前页对应的虚拟页数范围 $currentPageStart = ($page - 1) * $perPage + 1; $currentPageEnd = $page * $perPage; // 5. 筛选当前页需要展示的图片 $currentImages = collect(); $accumulatedWeight = 0; foreach ($weightedImages as $image) { $prevWeight = $accumulatedWeight; $accumulatedWeight += $image->weight; // 计算当前图片覆盖的虚拟页数区间 $imageStartPage = $prevWeight + 1; $imageEndPage = $accumulatedWeight; // 只要图片区间和当前页区间有交集,就加入当前页列表 if ($imageStartPage <= $currentPageEnd && $imageEndPage >= $currentPageStart) { $currentImages->push($image); } // 已经超过当前页范围,提前终止循环提升效率 if ($accumulatedWeight > $currentPageEnd) { break; } } // 6. 构建自定义分页器,保持原有分页功能的兼容性 $paginator = new \Illuminate\Pagination\LengthAwarePaginator( $currentImages, $totalWeight, $perPage, $page, [ 'path' => \Request::url(), 'query' => \Request::query(), ] ); return $paginator; }
效果验证
当perPage设为2时:
- 竖版图片每张占1个虚拟页,所以每页会展示2张竖版图片
- 横版图片每张占2个虚拟页,刚好填满一个分页,因此会单独占一页,不会和竖版图片混排
内容的提问来源于stack exchange,提问作者Terrabyte
相关产品推荐
相关产品推荐

