Laravel 10滚动分页分类场景返回错误数据及代码冗余问题
问题修复方案
问题根源
- 分类参数丢失:滚动加载的
fetch请求未携带当前页面的type参数,且paginated方法默认使用new作为type值,导致分页请求无法识别分类。 - 代码冗余:
index和paginated方法重复编写了大量查询构建逻辑,维护成本高。
修复步骤及代码修改
1. 提取公共查询构建方法
在PromptController中新增私有方法,统一处理查询逻辑,消除冗余:
private function buildPromptQuery(string $type, ?string $search) { $query = Prompt::query(); $date = Carbon::now()->subHours(96); switch ($type) { case 'hot': $query->where('created_at', '>=', $date) ->orderBy(DB::raw('views'), 'desc'); break; case 'top': $query->where('created_at', '>=', $date) ->orderBy(DB::raw('views + upvotes'), 'desc'); break; case 'new': $query->orderBy('created_at', 'desc'); break; default: $query->whereJsonContains('categories', $type); } if (!empty(trim($search))) { $query->whereFullText('prompt', $search); } return $query->where('deleted', 0) ->whereNotNull('prompt') ->where('prompt', '!=', ''); }
2. 简化index方法
调用公共方法重构index,保留缓存逻辑:
public function index(Request $request, $type = 'new') { $perPage = 60; $search = $request->get('search'); $cacheKey = 'prompts-' . $type . '-' . ($search ?? ''); $prompts = Cache::remember($cacheKey, 60, function () use ($search, $perPage, $type) { $query = $this->buildPromptQuery($type, $search); $this->logSQLQuery($type, $query, $search); return $query->paginate($perPage); }); $randomImageUrl = $this->getRandomImage(); return view('index', compact('prompts', 'randomImageUrl')); }
3. 修复paginated方法
修改为从查询参数获取type,确保分页请求能接收分类信息:
public function paginated(Request $request) { $perPage = 60; $search = $request->get('search'); $type = $request->get('type', 'new'); $query = $this->buildPromptQuery($type, $search); $prompts = $query->paginate($perPage); $prompts->appends(['search' => $search, 'type' => $type]); return view('partials.prompts', compact('prompts')); }
4. 更新前端JS,传递分类参数
修改滚动加载逻辑,从当前URL提取type并携带到分页请求:
<script src="https://cdnjs.cloudflare.com/ajax/libs/masonry/4.2.2/masonry.pkgd.min.js"></script> <script> const loadMorePlaceholder = document.querySelector('#load-more-placeholder'); let currentPage = {{ $prompts->currentPage() }}; let lastPage = {{ $prompts->lastPage() }}; let isLoading = false; const searchForm = document.querySelector('.search-box'); const searchButton = document.querySelector('#search-button'); const loadingSpinner = document.querySelector('#loading-spinner'); // 从URL路径提取当前分类type const pathParts = window.location.pathname.split('/').filter(part => part.trim() !== ''); const currentType = pathParts.length > 0 ? pathParts[0] : 'new'; searchForm.addEventListener('submit', () => { document.querySelector('#search-button-text').style.display = "none"; document.querySelector('#loading-spinner').style.display = 'inline-block'; }); function loadMoreImages() { if (isLoading || currentPage >= lastPage) return; isLoading = true; currentPage++; const search = new URLSearchParams(window.location.search).get('search'); const searchParam = search ? `&search=${encodeURIComponent(search)}` : ''; const typeParam = currentType ? `&type=${encodeURIComponent(currentType)}` : ''; fetch(`/prompts?page=${currentPage}${searchParam}${typeParam}`) .then(response => response.text()) .then(html => { document.querySelector('#image-container').insertAdjacentHTML('beforeend', html); isLoading = false; document.querySelector('#loading-spinner').style.display = 'none'; document.querySelector('#search-button-text').style.display = 'inline'; }); } function onScroll() { const rect = loadMorePlaceholder.getBoundingClientRect(); if (rect.top <= window.innerHeight) { loadMoreImages(); } } window.addEventListener('scroll', onScroll); </script>
5. 路由保持原有配置
无需修改web.php路由,当前配置已满足需求:
// 分页请求路由 Route::get('/prompts', [PromptController::class, 'paginated']); // 首页/分类路由 Route::get('/{type?}', [PromptController::class, 'index']);
内容的提问来源于stack exchange,提问作者Carol.Kar
相关产品推荐
相关产品推荐

