如何在Laravel Blade视图中实现无限滚动插件,滚动页面时自动从数据库加载更多商品
Got it, let's fix that slow page load with infinite scroll! Here's a step-by-step approach tailored to your Laravel setup:
1. Create a Backend API Endpoint for Paginated Products
First, we need a route that returns paginated product data (with rendered HTML snippets so we can easily append them to the page).
- Add this route to
routes/web.php:
Route::get('/products/just-for-you', [ProductController::class, 'justForYou'])->name('products.just-for-you');
- Then create the
justForYoumethod in yourProductController:
public function justForYou() { // Reuse your existing product filtering logic $products = filter_products(\App\Product::where('published', 1)->orderBy('id', 'desc'))->paginate(20); // Adjust items per page as needed // Render the product box partial for each item $html = ''; foreach ($products as $product) { $html .= view('frontend.partials.product_box_1', compact('product'))->render(); } return response()->json([ 'html' => $html, 'next_page_url' => $products->nextPageUrl() ]); }
This returns a JSON response with the HTML for the next set of products and the URL for the next page (if more items exist).
2. Modify Your Blade View for Initial Load & Infinite Scroll Container
Update your original Blade section to only load the first page of products, plus add a container for future items and a loading indicator:
@if (get_setting('best_selling') == 1) <section class="mb-4"> <div class="container"> <div class="px-2 py-4 px-md-4 py-md-3 bg-white shadow-sm rounded"> <div class="d-flex mb-3 align-items-baseline border-bottom"> <h3 class="h5 fw-700 mb-0"> <span class="border-bottom border-primary border-width-2 pb-3 d-inline-block">{{ translate('Just For You') }}</span> </h3> <a href="../search" class="ml-auto mr-0 btn btn-primary btn-sm shadow-md">{{ translate('View More') }}</a> </div> <!-- Initial products container --> <div class="row row-cols-xxl-7 row-cols-xl-6 row-cols-lg-5 row-cols-md-3 row-cols-2 gutters-10" id="products-container"> @foreach (filter_products(\App\Product::where('published', 1)->orderBy('id', 'desc'))->limit(20)->get() as $key => $product) <div> @include('frontend.partials.product_box_1',['product' => $product]) </div> @endforeach </div> <!-- Loading indicator --> <div class="text-center py-3 d-none" id="loading-more"> <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> <span class="ml-2">{{ translate('Loading more products...') }}</span> </div> </div> </div> </section> @endif
We swapped the limit(280) with limit(20) for the initial load, added an id to the products container, and included a loading spinner that shows when fetching more items.
3. Add Frontend JavaScript for Infinite Scroll
Add this script (put it at the end of your Blade view or in your main JS file) to handle scroll events and AJAX requests:
<script> let nextPageUrl = "{{ route('products.just-for-you') }}?page=2"; // Start with page 2 let isLoading = false; // Function to load more products function loadMoreProducts() { if (isLoading || !nextPageUrl) return; // Prevent duplicate requests isLoading = true; document.getElementById('loading-more').classList.remove('d-none'); fetch(nextPageUrl) .then(response => response.json()) .then(data => { // Append new product HTML to the container document.getElementById('products-container').insertAdjacentHTML('beforeend', data.html); // Update next page URL nextPageUrl = data.next_page_url; // Hide loading indicator document.getElementById('loading-more').classList.add('d-none'); isLoading = false; }) .catch(error => { console.error('Error loading products:', error); document.getElementById('loading-more').classList.add('d-none'); isLoading = false; }); } // Listen for scroll events window.addEventListener('scroll', () => { // Trigger load when user is 500px from page bottom (adjust offset as needed) if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight - 500) { loadMoreProducts(); } }); // Optional: Add a "Load More" button as fallback // document.getElementById('load-more-btn').addEventListener('click', loadMoreProducts); </script>
How this works:
- We start with
nextPageUrlpointing to page 2 of our API endpoint. - The scroll listener checks if the user is near the page bottom.
- When triggered, it fetches the next page, appends the HTML, updates the next page URL, and resets the loading state.
- The
isLoadingflag stops multiple concurrent requests.
4. Key Optimizations & Notes
- Adjust Pagination Size: Tweak
paginate(20)andlimit(20)to find the sweet spot between load speed and content density (15-30 items is ideal). - Debounce Scroll Events: If the scroll listener fires too often, add a debounce to limit calls:
let debounceTimer; window.addEventListener('scroll', () => { clearTimeout(debounceTimer); debounceTimer = setTimeout(() => { if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight - 500) { loadMoreProducts(); } }, 200); // Wait 200ms after last scroll before triggering }); - Error Handling: Extend the catch block to show a user-friendly error message (like a retry button) if requests fail.
- Lazy Load Images: Your existing
lazyloadsetup for product images is perfect—keep it to keep initial load times low.
This setup will let users scroll smoothly, loading products on demand instead of all at once, drastically improving initial page performance.
内容的提问来源于stack exchange,提问作者Sameer

