首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

Laravel + jQuery 實現 AJAX 無刷新分頁:完整前後端協作方案

     編輯:PHP 綜合知識

架構設計

  • 後端:Laravel Paginator + render() 視圖片段返回
  • 前端:jQuery AJAX 請求 + DOM 替換 + History API 支援
  • 核心優勢:保留 URL 狀態、支援瀏覽器前進後退、SEO 友好

後端控制器實現

photos = $photos;
    }
    
    // 頁面入口
    public function index() {
        $photos = $this->photos->paginate(12);
        return view('photos.index', compact('photos'));
    }
    
    // AJAX 分頁接口
    public function ajaxList(Request $request) {
        $page = $request->input('page', 1);
        $photos = $this->photos->paginate(12, ['*'], 'page', $page);
        
        if ($request->ajax()) {
            // 僅返回列表片段 + 分頁鏈接
            $html = view('photos._list', ['photos' => $photos])->render();
            $pagination = $photos->links('vendor.pagination.bootstrap-4')->render();
            
            return response()->json([
                'html' => $html,
                'pagination' => $pagination,
                'current_page' => $photos->currentPage(),
                'last_page' => $photos->lastPage()
            ]);
        }
        
        return view('photos.index', compact('photos'));
    }
}

視圖文件結構

resources/views/
├── photos/
│   ├── index.blade.php      # 主頁面
│   ├── _list.blade.php      # 列表片段(AJAX 返回)
│   └── _item.blade.php      # 單項片段(可選)

index.blade.php

@extends('layouts.app')

@section('content')

照片庫

@include('photos._list', ['photos' => $photos])
{!! $photos->links('vendor.pagination.bootstrap-4') !!}
@endsection @push('scripts') @endpush

_list.blade.php

@foreach($photos as $photo)
{{ $photo->title }}
{{ $photo->title }}
@endforeach

前端 JavaScript 實現

// public/js/photos.js
(function() {
    const $ = window.jQuery;
    const app = window.PhotosApp;
    let loading = false;
    
    // 初始化:綁定分頁鏈接點擊事件
    $(document).on('click', '#pagination-container a.page-link', function(e) {
        e.preventDefault();
        if (loading) return;
        
        const url = $(this).attr('href');
        const page = getPageFromUrl(url);
        if (page) loadPage(page);
    });
    
    // 從 URL 解析頁碼
    function getPageFromUrl(url) {
        const match = url.match(/[?&]page=(\d+)/);
        return match ? parseInt(match[1]) : null;
    }
    
    // 載入指定頁面
    function loadPage(page) {
        loading = true;
        showLoading();
        
        $.ajax({
            url: app.baseUrl,
            method: 'GET',
            data: { page: page },
            dataType: 'json',
            success: function(response) {
                // 更新列表
                $('#photos-list').html(response.html);
                
                // 更新分頁
                $('#pagination-container').html(response.pagination);
                
                // 更新狀態
                app.currentPage = response.current_page;
                app.lastPage = response.last_page;
                
                // 更新瀏覽器歷史(支援前進後退)
                const newUrl = updateUrlParameter(window.location.href, 'page', page);
                history.pushState({ page: page }, '', newUrl);
                
                hideLoading();
            },
            error: function(xhr) {
                console.error('Load failed:', xhr);
                alert('加載失敗,請重試');
                hideLoading();
            },
            complete: function() {
                loading = false;
            }
        });
    }
    
    // 瀏覽器前進後退支援
    window.addEventListener('popstate', function(e) {
        if (e.state && e.state.page) {
            loadPage(e.state.page);
        }
    });
    
    // URL 參數更新工具
    function updateUrlParameter(url, param, value) {
        const urlObj = new URL(url);
        urlObj.searchParams.set(param, value);
        return urlObj.toString();
    }
    
    function showLoading() {
        $('#photos-list').addClass('opacity-50');
        // 可添加 spinner
    }
    
    function hideLoading() {
        $('#photos-list').removeClass('opacity-50');
    }
    
    // 初始化
    $(function() {
        // 綁定選擇按鈕等業務邏輯
        $(document).on('click', '.select-photo', function() {
            const id = $(this).data('id');
            // 業務處理...
        });
    });
})();

路由配置

// routes/web.php
Route::get('/photos', 'PhotoController@index')->name('photos.index');
Route::get('/photos/ajax', 'PhotoController@ajaxList')->name('photos.ajax');

進階優化:無限滾動(Infinite Scroll)

// 替換分頁點擊為滾動加載
let loading = false;
$(window).on('scroll', function() {
    if (loading) return;
    if ($(window).scrollTop() + $(window).height() > $(document).height() - 200) {
        if (app.currentPage < app.lastPage) {
            loadPage(app.currentPage + 1);
        }
    }
});

// 修改 loadPage 追加而非替換
function loadPage(page) {
    // ...
    success: function(response) {
        if (page === 1) {
            $('#photos-list').html(response.html);
        } else {
            $('#photos-list').append(response.html); // 追加模式
        }
        // ...
    }
}

關鍵最佳實踐

實踐說明
History APIpushState 保持 URL 同步,支援分享、刷新、前進後退
片段渲染後端僅返回 _list 片段,減少傳輸體積
Loading 狀態防止重複請求,提升體驗
錯誤處理網絡異常友好提示,不阻塞頁面
CSRF TokenLaravel 自動驗證 AJAX 請求頭 X-CSRF-TOKEN

總結

  • Laravel Paginator 原生支援 AJAX 分頁,配合 render() 輕鬆輸出片段
  • jQuery 負責 DOM 更新與 History API 管理,代碼量極少
  • 核心模式:請求 → JSON(HTML片段+分頁) → DOM替換 → URL同步
  • 無限滾動只需將「替換」改為「追加」,觸發條件從點擊改為滾動

這套方案零依賴第三方分頁插件,完全掌控前後端交互細節,是 Laravel 專案實現無刷新分頁的標準最佳實踐。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved